breck7 / scrollsdk

Build on top of Scroll.
https://sdk.scroll.pub
380 stars 17 forks source link

Stumpdown inside Stump? #128

Closed getflourish closed 3 years ago

getflourish commented 3 years ago

Would it be possible to use Markdown inside HTML?

Similar to how the bern tag works, but maybe referencing a different / imported Grammar?

For example:

html
 body
  markdown
   # Title
   This is **some** text
  article
   section
    … 
breck7 commented 3 years ago

Yes, is roughly possible [today](https://jtree.treenotation.org/designer/#grammar%0A%20tooling%20onsave%20jtree%20build%20produceLang%20stump%0A%20anyCell%0A%20markdownCell%0A%20%20highlightScope%20string%0A%20keywordCell%0A%20emptyCell%0A%20extraCell%0A%20%20highlightScope%20invalid%0A%20anyHtmlContentCell%0A%20%20highlightScope%20string%0A%20attributeValueCell%0A%20%20highlightScope%20constant.language%0A%20componentTagNameCell%0A%20%20highlightScope%20variable.function%0A%20%20extends%20keywordCell%0A%20htmlTagNameCell%0A%20%20highlightScope%20variable.function%0A%20%20extends%20keywordCell%0A%20%20enum%20a%20abbr%20address%20area%20article%20aside%20b%20base%20bdi%20bdo%20blockquote%20body%20br%20button%20canvas%20caption%20code%20col%20colgroup%20datalist%20dd%20del%20details%20dfn%20dialog%20div%20dl%20dt%20em%20embed%20fieldset%20figure%20footer%20form%20h1%20h2%20h3%20h4%20h5%20h6%20head%20header%20hgroup%20hr%20html%20i%20iframe%20img%20input%20ins%20kbd%20keygen%20label%20legend%20li%20link%20main%20map%20mark%20menu%20menuitem%20meta%20meter%20nav%20noscript%20object%20ol%20optgroup%20option%20output%20p%20param%20pre%20progress%20q%20rb%20rp%20rt%20rtc%20ruby%20s%20samp%20script%20section%20select%20small%20source%20span%20strong%20styleTag%20sub%20summary%20sup%20table%20tbody%20td%20template%20textarea%20tfoot%20th%20thead%20time%20titleTag%20tr%20track%20u%20ul%20var%20video%20wbr%0A%20htmlAttributeNameCell%0A%20%20highlightScope%20entity.name.type%0A%20%20extends%20keywordCell%0A%20%20enum%20accept%20accept-charset%20accesskey%20action%20align%20alt%20async%20autocomplete%20autofocus%20autoplay%20bgcolor%20border%20charset%20checked%20class%20color%20cols%20colspan%20content%20contenteditable%20controls%20coords%20datetime%20default%20defer%20dir%20dirname%20disabled%20download%20draggable%20dropzone%20enctype%20for%20formaction%20headers%20height%20hidden%20high%20href%20hreflang%20http-equiv%20id%20ismap%20kind%20lang%20list%20loop%20low%20max%20maxlength%20media%20method%20min%20multiple%20muted%20name%20novalidate%20onabort%20onafterprint%20onbeforeprint%20onbeforeunload%20onblur%20oncanplay%20oncanplaythrough%20onchange%20onclick%20oncontextmenu%20oncopy%20oncuechange%20oncut%20ondblclick%20ondrag%20ondragend%20ondragenter%20ondragleave%20ondragover%20ondragstart%20ondrop%20ondurationchange%20onemptied%20onended%20onerror%20onfocus%20onhashchange%20oninput%20oninvalid%20onkeydown%20onkeypress%20onkeyup%20onload%20onloadeddata%20onloadedmetadata%20onloadstart%20onmousedown%20onmousemove%20onmouseout%20onmouseover%20onmouseup%20onmousewheel%20onoffline%20ononline%20onpagehide%20onpageshow%20onpaste%20onpause%20onplay%20onplaying%20onpopstate%20onprogress%20onratechange%20onreset%20onresize%20onscroll%20onsearch%20onseeked%20onseeking%20onselect%20onstalled%20onstorage%20onsubmit%20onsuspend%20ontimeupdate%20ontoggle%20onunload%20onvolumechange%20onwaiting%20onwheel%20open%20optimum%20pattern%20placeholder%20poster%20preload%20readonly%20rel%20required%20reversed%20rows%20rowspan%20sandbox%20scope%20selected%20shape%20size%20sizes%20spellcheck%20src%20srcdoc%20srclang%20srcset%20start%20step%20style%20tabindex%20target%20title%20translate%20type%20usemap%20value%20width%20wrap%0A%20bernKeywordCell%0A%20%20enum%20bern%0A%20%20extends%20keywordCell%0A%20stumpNode%0A%20%20root%0A%20%20description%20A%20prefix%20Tree%20Language%20that%20compiles%20to%20HTML.%0A%20%20catchAllNodeType%20errorNode%0A%20%20inScope%20htmlTagNode%20blankLineNode%20markdownNode%0A%20%20example%0A%20%20%20div%0A%20%20%20%20h1%20hello%20world%0A%20%20compilesTo%20html%0A%20%20javascript%0A%20%20%20compile()%20%7B%0A%20%20%20%20return%20this.toHtml()%0A%20%20%20%7D%0A%20%20%20_getHtmlJoinByCharacter()%20%7B%0A%20%20%20%20%20return%20%22%22%0A%20%20%20%7D%0A%20markdownNode%0A%20%20crux%20markdown%0A%20%20catchAllNodeType%20markdownContentNode%0A%20%20cells%20keywordCell%0A%20markdownContentNode%0A%20%20catchAllCellType%20markdownCell%0A%20blankLineNode%0A%20%20pattern%20%5E%24%0A%20%20tags%20doNotSynthesize%0A%20%20cells%20emptyCell%0A%20%20javascript%0A%20%20%20_toHtml()%20%7B%0A%20%20%20%20return%20%22%22%0A%20%20%20%7D%0A%20%20%20getTextContent()%20%7Breturn%20%22%22%7D%0A%20htmlTagNode%0A%20%20inScope%20markdownNode%20bernNode%20htmlTagNode%20htmlAttributeNode%20blankLineNode%0A%20%20catchAllCellType%20anyHtmlContentCell%0A%20%20cells%20htmlTagNameCell%0A%20%20javascript%0A%20%20%20getTag()%20%7B%0A%20%20%20%20%2F%2F%20we%20need%20to%20remove%20the%20%22Tag%22%20bit%20to%20handle%20the%20style%20and%20title%20attribute%2Ftag%20conflict.%0A%20%20%20%20const%20firstWord%20%3D%20this.getFirstWord()%0A%20%20%20%20const%20map%20%3D%20%7B%0A%20%20%20%20%20titleTag%3A%20%22title%22%2C%0A%20%20%20%20%20styleTag%3A%20%22style%22%0A%20%20%20%20%7D%0A%20%20%20%20return%20map%5BfirstWord%5D%20%7C%7C%20firstWord%0A%20%20%20%7D%0A%20%20%20_getHtmlJoinByCharacter()%20%7B%0A%20%20%20%20return%20%22%22%0A%20%20%20%7D%0A%20%20%20toHtmlWithSuids()%20%7B%0A%20%20%20%20return%20this._toHtml(undefined%2C%20true)%0A%20%20%20%7D%0A%20%20%20_getOneLiner()%20%7B%0A%20%20%20%20const%20oneLinerWords%20%3D%20this.getWordsFrom(1)%0A%20%20%20%20return%20oneLinerWords.length%20%3F%20oneLinerWords.join(%22%20%22)%20%3A%20%22%22%0A%20%20%20%7D%0A%20%20%20getTextContent()%20%7B%0A%20%20%20%20%20return%20this._getOneLiner()%0A%20%20%20%7D%0A%20%20%20shouldCollapse()%20%7B%0A%20%20%20%20return%20this.has(%22collapse%22)%0A%20%20%20%7D%0A%20%20%20_toHtml(indentCount%2C%20withSuid)%20%7B%0A%20%20%20%20const%20tag%20%3D%20this.getTag()%0A%20%20%20%20const%20children%20%3D%20this.map(child%20%3D%3E%20child._toHtml(indentCount%20%2B%201%2C%20withSuid)).join(%22%22)%0A%20%20%20%20const%20attributesStr%20%3D%20this.filter(node%20%3D%3E%20node.isAttributeNode)%0A%20%20%20%20%20.map(child%20%3D%3E%20child.getAttribute())%0A%20%20%20%20%20.join(%22%22)%0A%20%20%20%20const%20indent%20%3D%20%22%20%22.repeat(indentCount)%0A%20%20%20%20const%20collapse%20%3D%20this.shouldCollapse()%0A%20%20%20%20const%20indentForChildNodes%20%3D%20!collapse%20%26%26%20this.getChildInstancesOfNodeTypeId(%22htmlTagNode%22).length%20%3E%200%0A%20%20%20%20const%20suid%20%3D%20withSuid%20%3F%20%60%20stumpUid%3D%22%24%7Bthis._getUid()%7D%22%60%20%3A%20%22%22%0A%20%20%20%20const%20oneLiner%20%3D%20this._getOneLiner()%0A%20%20%20%20return%20%60%24%7B!collapse%20%3F%20indent%20%3A%20%22%22%7D%3C%24%7Btag%7D%24%7BattributesStr%7D%24%7Bsuid%7D%3E%24%7BoneLiner%7D%24%7BindentForChildNodes%20%3F%20%22%5Cn%22%20%3A%20%22%22%7D%24%7Bchildren%7D%3C%2F%24%7Btag%7D%3E%24%7Bcollapse%20%3F%20%22%22%20%3A%20%22%5Cn%22%7D%60%0A%20%20%20%7D%0A%20%20%20removeCssStumpNode()%20%7B%0A%20%20%20%20return%20this.removeStumpNode()%0A%20%20%20%7D%0A%20%20%20removeStumpNode()%20%7B%0A%20%20%20%20this.getShadow().removeShadow()%0A%20%20%20%20return%20this.destroy()%0A%20%20%20%7D%0A%20%20%20getNodeByGuid(guid)%20%7B%0A%20%20%20%20return%20this.getTopDownArray().find(node%20%3D%3E%20node._getUid()%20%3D%3D%3D%20guid)%0A%20%20%20%7D%0A%20%20%20addClassToStumpNode(className)%20%7B%0A%20%20%20%20const%20classNode%20%3D%20this.touchNode(%22class%22)%0A%20%20%20%20const%20words%20%3D%20classNode.getWordsFrom(1)%0A%20%20%20%20%2F%2F%20note%3A%20we%20call%20add%20on%20shadow%20regardless%2C%20because%20at%20the%20moment%20stump%20may%20have%20gotten%20out%20of%0A%20%20%20%20%2F%2F%20sync%20with%20shadow%2C%20if%20things%20modified%20the%20dom.%20todo%3A%20cleanup.%0A%20%20%20%20this.getShadow().addClassToShadow(className)%0A%20%20%20%20if%20(words.includes(className))%20return%20this%0A%20%20%20%20words.push(className)%0A%20%20%20%20classNode.setContent(words.join(this.getWordBreakSymbol()))%0A%20%20%20%20return%20this%0A%20%20%20%7D%0A%20%20%20removeClassFromStumpNode(className)%20%7B%0A%20%20%20%20const%20classNode%20%3D%20this.getNode(%22class%22)%0A%20%20%20%20if%20(!classNode)%20return%20this%0A%20%20%20%20const%20newClasses%20%3D%20classNode.getWords().filter(word%20%3D%3E%20word%20!%3D%3D%20className)%0A%20%20%20%20if%20(!newClasses.length)%20classNode.destroy()%0A%20%20%20%20else%20classNode.setContent(newClasses.join(%22%20%22))%0A%20%20%20%20this.getShadow().removeClassFromShadow(className)%0A%20%20%20%20return%20this%0A%20%20%20%7D%0A%20%20%20stumpNodeHasClass(className)%20%7B%0A%20%20%20%20const%20classNode%20%3D%20this.getNode(%22class%22)%0A%20%20%20%20return%20classNode%20%26%26%20classNode.getWords().includes(className)%20%3F%20true%20%3A%20false%0A%20%20%20%7D%0A%20%20%20isStumpNodeCheckbox()%20%7B%0A%20%20%20%20return%20this.get(%22type%22)%20%3D%3D%3D%20%22checkbox%22%0A%20%20%20%7D%0A%20%20%20getShadow()%20%7B%0A%20%20%20%20if%20(!this._shadow)%20%7B%0A%20%20%20%20%20const%20shadowClass%20%3D%20this.getShadowClass()%0A%20%20%20%20%20this._shadow%20%3D%20new%20shadowClass(this)%0A%20%20%20%20%7D%0A%20%20%20%20return%20this._shadow%0A%20%20%20%7D%0A%20%20%20insertCssChildNode(text%2C%20index)%20%7B%0A%20%20%20%20return%20this.insertChildNode(text%2C%20index)%0A%20%20%20%7D%0A%20%20%20insertChildNode(text%2C%20index)%20%7B%0A%20%20%20%20const%20singleNode%20%3D%20new%20jtree.TreeNode(text).getChildren()%5B0%5D%0A%20%20%20%20const%20newNode%20%3D%20this.insertLineAndChildren(singleNode.getLine()%2C%20singleNode.childrenToString()%2C%20index)%0A%20%20%20%20const%20stumpNodeIndex%20%3D%20this.getChildInstancesOfNodeTypeId(%22htmlTagNode%22).indexOf(newNode)%0A%20%20%20%20this.getShadow().insertHtmlNode(newNode%2C%20stumpNodeIndex)%0A%20%20%20%20return%20newNode%0A%20%20%20%7D%0A%20%20%20isInputType()%20%7B%0A%20%20%20%20return%20%5B%22input%22%2C%20%22textarea%22%5D.includes(this.getTag())%20%7C%7C%20this.get(%22contenteditable%22)%20%3D%3D%3D%20%22true%22%0A%20%20%20%7D%0A%20%20%20findStumpNodeByChild(line)%20%7B%0A%20%20%20%20return%20this.findStumpNodesByChild(line)%5B0%5D%0A%20%20%20%7D%0A%20%20%20findStumpNodeByChildString(line)%20%7B%0A%20%20%20%20return%20this.getTopDownArray().find(node%20%3D%3E%0A%20%20%20%20%20node%0A%20%20%20%20%20%20.map(child%20%3D%3E%20child.getLine())%0A%20%20%20%20%20%20.join(%22%5Cn%22)%0A%20%20%20%20%20%20.includes(line)%0A%20%20%20%20)%0A%20%20%20%7D%0A%20%20%20findStumpNodeByFirstWord(firstWord)%20%7B%0A%20%20%20%20return%20this._findStumpNodesByBase(firstWord)%5B0%5D%0A%20%20%20%7D%0A%20%20%20_findStumpNodesByBase(firstWord)%20%7B%0A%20%20%20%20return%20this.getTopDownArray().filter(node%20%3D%3E%20node.doesExtend(%22htmlTagNode%22)%20%26%26%20node.getFirstWord()%20%3D%3D%3D%20firstWord)%0A%20%20%20%7D%0A%20%20%20hasLine(line)%20%7B%0A%20%20%20%20return%20this.getChildren().some(node%20%3D%3E%20node.getLine()%20%3D%3D%3D%20line)%0A%20%20%20%7D%0A%20%20%20findStumpNodesByChild(line)%20%7B%0A%20%20%20%20return%20this.getTopDownArray().filter(node%20%3D%3E%20node.doesExtend(%22htmlTagNode%22)%20%26%26%20node.hasLine(line))%0A%20%20%20%7D%0A%20%20%20findStumpNodesWithClass(className)%20%7B%0A%20%20%20%20return%20this.getTopDownArray().filter(%0A%20%20%20%20%20node%20%3D%3E%0A%20%20%20%20%20%20node.doesExtend(%22htmlTagNode%22)%20%26%26%0A%20%20%20%20%20%20node.has(%22class%22)%20%26%26%0A%20%20%20%20%20%20node%0A%20%20%20%20%20%20%20.getNode(%22class%22)%0A%20%20%20%20%20%20%20.getWords()%0A%20%20%20%20%20%20%20.includes(className)%0A%20%20%20%20)%0A%20%20%20%7D%0A%20%20%20getShadowClass()%20%7B%0A%20%20%20%20return%20this.getParent().getShadowClass()%0A%20%20%20%7D%0A%20%20%20%2F%2F%20todo%3A%20should%20not%20be%20here%0A%20%20%20getStumpNodeTreeComponent()%20%7B%0A%20%20%20%20return%20this._treeComponent%20%7C%7C%20this.getParent().getStumpNodeTreeComponent()%0A%20%20%20%7D%0A%20%20%20%2F%2F%20todo%3A%20should%20not%20be%20here%0A%20%20%20setStumpNodeTreeComponent(treeComponent)%20%7B%0A%20%20%20%20this._treeComponent%20%3D%20treeComponent%0A%20%20%20%20return%20this%0A%20%20%20%7D%0A%20%20%20setStumpNodeCss(css)%20%7B%0A%20%20%20%20this.getShadow().setShadowCss(css)%0A%20%20%20%20return%20this%0A%20%20%20%7D%0A%20%20%20getStumpNodeCss(prop)%20%7B%0A%20%20%20%20return%20this.getShadow().getShadowCss(prop)%0A%20%20%20%7D%0A%20%20%20getStumpNodeAttr(key)%20%7B%0A%20%20%20%20return%20this.get(key)%0A%20%20%20%7D%0A%20%20%20setStumpNodeAttr(key%2C%20value)%20%7B%0A%20%20%20%20%2F%2F%20todo%0A%20%20%20%20return%20this%0A%20%20%20%7D%0A%20%20%20toHtml()%20%7B%0A%20%20%20%20return%20this._toHtml()%0A%20%20%20%7D%0A%20errorNode%0A%20%20baseNodeType%20errorNode%0A%20componentDefinitionNode%0A%20%20extends%20htmlTagNode%0A%20%20pattern%20%5E%5Ba-zA-Z0-9_%5D%2BComponent%0A%20%20cells%20componentTagNameCell%0A%20%20javascript%0A%20%20%20getTag()%20%7B%0A%20%20%20%20return%20%22div%22%0A%20%20%20%7D%0A%20htmlAttributeNode%0A%20%20javascript%0A%20%20%20_toHtml()%20%7B%0A%20%20%20%20return%20%22%22%0A%20%20%20%7D%0A%20%20%20getTextContent()%20%7Breturn%20%22%22%7D%0A%20%20%20getAttribute()%20%7B%0A%20%20%20%20return%20%60%20%24%7Bthis.getFirstWord()%7D%3D%22%24%7Bthis.getContent()%7D%22%60%0A%20%20%20%7D%0A%20%20boolean%20isAttributeNode%20true%0A%20%20boolean%20isTileAttribute%20true%0A%20%20catchAllNodeType%20errorNode%0A%20%20catchAllCellType%20attributeValueCell%0A%20%20cells%20htmlAttributeNameCell%0A%20stumpExtendedAttributeNameCell%0A%20%20extends%20htmlAttributeNameCell%0A%20%20enum%20collapse%20blurCommand%20changeCommand%20clickCommand%20contextMenuCommand%20doubleClickCommand%20lineClickCommand%20lineShiftClickCommand%20shiftClickCommand%0A%20stumpExtendedAttributeNode%0A%20%20description%20Node%20types%20not%20present%20in%20HTML%20but%20included%20in%20stump.%0A%20%20extends%20htmlAttributeNode%0A%20%20cells%20stumpExtendedAttributeNameCell%0A%20lineOfHtmlContentNode%0A%20%20boolean%20isTileAttribute%20true%0A%20%20catchAllNodeType%20lineOfHtmlContentNode%0A%20%20catchAllCellType%20anyHtmlContentCell%0A%20%20javascript%0A%20%20%20getTextContent()%20%7Breturn%20this.getLine()%7D%0A%20bernNode%0A%20%20boolean%20isTileAttribute%20true%0A%20%20todo%20Rename%20this%20node%20type%0A%20%20description%20This%20is%20a%20node%20where%20you%20can%20put%20any%20HTML%20content.%20It%20is%20called%20%22bern%22%20until%20someone%20comes%20up%20with%20a%20better%20name.%0A%20%20catchAllNodeType%20lineOfHtmlContentNode%0A%20%20javascript%0A%20%20%20_toHtml()%20%7B%0A%20%20%20%20return%20this.childrenToString()%0A%20%20%20%7D%0A%20%20%20getTextContent()%20%7Breturn%20%22%22%7D%0A%20%20cells%20bernKeywordCell%0Asample%0A%20html%0A%20%20body%0A%20%20%20markdown%0A%20%20%20%20%23%20Title%0A%20%20%20%20This%20is%20**some**%20text%0A%20%20%20article%0A%20%20%20%20section).

You could just use a markdown lib to compile those blocks.

You can concatenate 2 grammars to accomplish this as well. There is not yet a built in mechanism in Grammar to import files, but that's probably something to add, so that it would be easier to rapidly build languages that combine multiple stable grammars.

breck7 commented 3 years ago

Going to close this to cleanup the issues. But it's another good vote for easier grammar concatenation. A number of things in the pipeline will make that more useful.