Code highlighting in preview pane

Hi,

I am not sure, if this topic is already existing here, but I could not find it.
Perhaps anyone can need something like this: Code highlighting in the export and also in the preview.

Looks like this (in this example are simpy a few lines of TB code and JavaScript Code):

Can you attach the document that you used to generate the screenshot?

Yes. Here it is!
prism_test.tbx (158.2 KB)

I have marked all notes and lines red, that are important for this to happen.
The prism.css and prism.js are from the website https://prismjs.com/

You can choose there, which languages should be highlighted. The two files in this tbx are rather minimalisticā€¦ if you want more ore different languages, you can build your own prism.js und prism.css thereā€¦

Btwā€¦ I stole the idea here at the DT Forum, and simply adjusted it a little bit for TB.

Very cool!

BTW, it seems that you have to run the export once for the preview command to pick up the generated css files.

Iā€™m rather confused at how the preview command finds these .jss files. How does it know what to consider the document root???

It also took me some time to figure this out :rofl:
But in the end it workedā€¦

Not quite sure, but very likely it works that way.

Preview uses - like HTML in general - css and JavaScript to style a document and to interact with it. So you only need to tell the HTML, where those files are. This happens with the 2 code lines in the ā€žTestā€œ note, that I marked red. The 2 ā€žprismā€œ notes are saved as prism.css and prism.js and use the ā€žTextā€œ Template, so that really only the $Text is saved, without the title or any other stuff. Hereby is guaranteed, that those files are really ā€žcleanā€œ.
Root is always the top level of a TB document, and the export code ^root^ point to this location, but not absulutely, but relatively. In the case of this document, you could the ^root^ expression, because everything is at root level. This gets interesting, when your notes, that should be styled, are located in containersā€¦

HTH

Thank-you for sharing! This is fantastic. Iā€™m testing out Tinderbox as part of a workflow for producing lecture material/slides in Jupyter notebooks and this goes a long way toward making readable code snippets in Tinderbox.
Lisa

1 Like

Speaking of which, Iā€™m wrestling a bit with Jupiter Notebook and gensim on a long-range Tinderbox project. If you (or other bystanders) can help get me unstuck, that would be great. Email bernstein@eastgate.com

Hey, would be very helpful if you have an updated working version of this?

I just exchanged the Markdown prototype for a newer prototype, now it seems to work. Can you try it again with the attached file?

prism_test.tbx (164.5 KB)

Hi Kay,

Apologies, last got buried in inbox.

If I download this, click Test, and then Preview, I get:

/* PrismJS 1.16.0 https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+applescript+markdown+python */ var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(g){var c=/\blang(?:uage)?-([\w-]+)\b/i,a=0,C={manual:g.Prism&&g.Prism.manual,disableWorkerMessageHandler:g.Prism&&g.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof M?new M(e.type,C.util.encode(e.content),e.alias):Array.isArray(e)?e.map(C.util.encode):e.replace(/&/g,"&").replace(/e.length)return;if(!(k instanceof M)){if(f&&y!=a.length-1){if(c.lastIndex=v,!(x=c.exec(e)))break;for(var b=x.index+(h?x[1].length:0),w=x.index+x[0].length,A=y,P=v,O=a.length;A"+n.content+""},!g.document)return g.addEventListener&&(C.disableWorkerMessageHandler||g.addEventListener("message",function(e){var a=JSON.parse(e.data),n=a.language,t=a.code,r=a.immediateClose;g.postMessage(C.highlight(t,C.languages[n],n)),r&&g.close()},!1)),C;var e=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return e&&(C.filename=e.src,C.manual||e.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(C.highlightAll):window.setTimeout(C.highlightAll,16):document.addEventListener("DOMContentLoaded",C.highlightAll))),C}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); Prism.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype://i,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/i,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var n={"included-cdata":{pattern://i,inside:s}};n["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var i={};i[a]={pattern:RegExp("(<__[\\s\\S]*?>)(?:\\s*|[\\s\\S])*?(?=<\\/__>)".replace(/__/g,a),"i"),lookbehind:!0,greedy:!0,inside:n},Prism.languages.insertBefore("markup","cdata",i)}}),Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup; !function(s){var e=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;s.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+?[\s\S]*?(?:;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:RegExp("url\\((?:"+e.source+"|.*?)\\)","i"),selector:RegExp("[^{}\\s](?:[^{};\"']|"+e.source+")*?(?=\\s*\\{)"),string:{pattern:e,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var a=s.languages.markup;a&&(a.tag.addInlined("style","css"),s.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:a.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:s.languages.css}},alias:"language-css"}},a.tag))}(Prism); Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/}; Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},{pattern:/(^|[^.])\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],number:/\b(?:(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+)n?|\d+n|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,function:/[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,operator:/-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=\s*($|[\r\n,.;})\]]))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|[^\\`])*`/,greedy:!0,inside:{interpolation:{pattern:/\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.js=Prism.languages.javascript; Prism.languages.applescript={comment:[/\(\*(?:\(\*[\s\S]*?\*\)|[\s\S])*?\*\)/,/--.+/,/#.+/],string:/"(?:\\.|[^"\\\r\n])*"/,number:/(?:\b\d+\.?\d*|\B\.\d+)(?:e-?\d+)?\b/i,operator:[/[&=ā‰ ā‰¤ā‰„*+\-\/Ć·^]|[<>]=?/,/\b(?:(?:start|begin|end)s? with|(?:(?:does not|doesn't) contain|contains?)|(?:is|isn't|is not) (?:in|contained by)|(?:(?:is|isn't|is not) )?(?:greater|less) than(?: or equal)?(?: to)?|(?:(?:does not|doesn't) come|comes) (?:before|after)|(?:is|isn't|is not) equal(?: to)?|(?:(?:does not|doesn't) equal|equals|equal to|isn't|is not)|(?:a )?(?:ref(?: to)?|reference to)|(?:and|or|div|mod|as|not))\b/],keyword:/\b(?:about|above|after|against|apart from|around|aside 

Weird thing is if I click on Test with preview already selected, it renders some of it OK briefly before reverting to outputting the raw code again.

Any ideas what Iā€™m missing?

Okā€¦ next try :slight_smile:
There was a little mistake obviously.
I fixed it and I downloaded also the up-to-date version of prism into the file.

So now you need to do an export of your note once, so that Tinderbox can create the .css and .js files on your drive.

After this you should find something on your drive:

2022-09-27_14-22-04

And then, the preview should look like:

prism_test.tbx (181.6 KB)

And you have to assign the ā€œMarkdownā€ prototype to the ā€œTestā€ note, so that all those heading will be displayed accordingly. I forgot this, so you see the ā€œ#ā€ in the preview, instead of a nice heading. But thatā€™s easy to fix, I thinkā€¦

1 Like

Neat. If you donā€™t want to export you can try using a trick learned from the Zero-config template in hints. Firstly, as wereā€™s using in-doc refs, having two notes both called prism could confuse the app. I renamed them to ā€˜prisn-cssā€™ and ā€˜prism-jsā€™. Another approach to avoid renaming could be to reference the note via $ID instead of path (which I donā€™t do here).

Now, in the HTML templates, the CSS reference becomes:

<style>^value($Text(/Codestyle/prism-css))^</style>

and the script reference becomes:

<script>^value($Text(/Codestyle/prism-js))^</script>

Now the test noteā€™s code is formatted in review with zero export.

A note of caution though against using very complex JavaScript in this manner. The preview pane is essentially a window using Apple WebKit (as used in Safari). But the WebKit is for rendering WebPages as opposed to functioning as a full web browser app.

1 Like

I will try this.

Didnā€™t know this technique yet.

Btw, the both notes ā€žprismā€œ have the same name, but different extensions. I think, in your example the notes are addressed with only their note names, right? Then it obviously makes sense to name them differently.

Thanks a lot :pray:

Yes. In your case this mattered less as you were exporting them with different exported file extension.

FWIW, I didnā€™t know this was possible until I just tried. :slight_smile: I got the idea after doing more testing on various states of Preview use. In truth, if I needed this, Iā€™d likely go with you solution and not this one. But thereā€™s bound to be at least one person who really doesnā€™t want to export anything.

1 Like