1 line
5.4 KiB
JavaScript
1 line
5.4 KiB
JavaScript
import{parser}from"@lezer/xml";import{LRLanguage,indentNodeProp,foldNodeProp,bracketMatchingHandle,LanguageSupport,syntaxTree}from"@codemirror/language";function tagName(e,t){let n=t&&t.getChild("TagName");return n?e.sliceString(n.from,n.to):""}function elementName(e,t){let n=t&&t.firstChild;return n&&"OpenTag"==n.name?tagName(e,n):""}function attrName(e,t,n){let l=t&&t.getChildren("Attribute").find((e=>e.from<=n&&e.to>=n)),a=l&&l.getChild("AttributeName");return a?e.sliceString(a.from,a.to):""}function findParentElement(e){for(let t=e&&e.parent;t;t=t.parent)if("Element"==t.name)return t;return null}function findLocation(e,t){var n;let l=syntaxTree(e).resolveInner(t,-1),a=null;for(let e=l;!a&&e.parent;e=e.parent)"OpenTag"!=e.name&&"CloseTag"!=e.name&&"SelfClosingTag"!=e.name&&"MismatchedCloseTag"!=e.name||(a=e);if(a&&(a.to>t||a.lastChild.type.isError)){let e=a.parent;if("TagName"==l.name)return"CloseTag"==a.name||"MismatchedCloseTag"==a.name?{type:"closeTag",from:l.from,context:e}:{type:"openTag",from:l.from,context:findParentElement(e)};if("AttributeName"==l.name)return{type:"attrName",from:l.from,context:a};if("AttributeValue"==l.name)return{type:"attrValue",from:l.from,context:a};let n=l==a||"Attribute"==l.name?l.childBefore(t):l;return"StartTag"==(null==n?void 0:n.name)?{type:"openTag",from:t,context:findParentElement(e)}:"StartCloseTag"==(null==n?void 0:n.name)&&n.to<=t?{type:"closeTag",from:t,context:e}:"Is"==(null==n?void 0:n.name)?{type:"attrValue",from:t,context:a}:n?{type:"attrName",from:t,context:a}:null}if("StartCloseTag"==l.name)return{type:"closeTag",from:t,context:l.parent};for(;l.parent&&l.to==t&&!(null===(n=l.lastChild)||void 0===n?void 0:n.type.isError);)l=l.parent;return"Element"==l.name||"Text"==l.name||"Document"==l.name?{type:"tag",from:t,context:"Element"==l.name?l:findParentElement(l)}:null}class Element{constructor(e,t,n){this.attrs=t,this.attrValues=n,this.children=[],this.name=e.name,this.completion=Object.assign(Object.assign({type:"type"},e.completion||{}),{label:this.name}),this.openCompletion=Object.assign(Object.assign({},this.completion),{label:"<"+this.name}),this.closeCompletion=Object.assign(Object.assign({},this.completion),{label:"</"+this.name+">",boost:2}),this.closeNameCompletion=Object.assign(Object.assign({},this.completion),{label:this.name+">"}),this.text=e.textContent?e.textContent.map((e=>({label:e,type:"text"}))):[]}}const Identifier=/^[:\-\.\w\u00b7-\uffff]*$/;function attrCompletion(e){return Object.assign(Object.assign({type:"property"},e.completion||{}),{label:e.name})}function valueCompletion(e){return"string"==typeof e?{label:`"${e}"`,type:"constant"}:/^"/.test(e.label)?e:Object.assign(Object.assign({},e),{label:`"${e.label}"`})}function completeFromSchema(e,t){let n=[],l=[],a=Object.create(null);for(let e of t){let t=attrCompletion(e);n.push(t),e.global&&l.push(t),e.values&&(a[e.name]=e.values.map(valueCompletion))}let o=[],r=[],i=Object.create(null);for(let t of e){let e=l,m=a;t.attributes&&(e=e.concat(t.attributes.map((e=>"string"==typeof e?n.find((t=>t.label==e))||{label:e,type:"property"}:(e.values&&(m==a&&(m=Object.create(m)),m[e.name]=e.values.map(valueCompletion)),attrCompletion(e))))));let s=new Element(t,e,m);i[s.name]=s,o.push(s),t.top&&r.push(s)}r.length||(r=o);for(let t=0;t<o.length;t++){let n=e[t],l=o[t];if(n.children)for(let e of n.children)i[e]&&l.children.push(i[e]);else l.children=o}return e=>{var t;let{doc:n}=e.state,m=findLocation(e.state,e.pos);if(!m||"tag"==m.type&&!e.explicit)return null;let{type:s,from:p,context:u}=m;if("openTag"==s){let e=r,t=elementName(n,u);if(t){let n=i[t];e=(null==n?void 0:n.children)||o}return{from:p,options:e.map((e=>e.completion)),validFor:Identifier}}if("closeTag"==s){let l=elementName(n,u);return l?{from:p,to:e.pos+(">"==n.sliceString(e.pos,e.pos+1)?1:0),options:[(null===(t=i[l])||void 0===t?void 0:t.closeNameCompletion)||{label:l+">",type:"type"}],validFor:Identifier}:null}if("attrName"==s){let e=i[tagName(n,u)];return{from:p,options:(null==e?void 0:e.attrs)||l,validFor:Identifier}}if("attrValue"==s){let t=attrName(n,u,p);if(!t)return null;let l=i[tagName(n,u)],o=((null==l?void 0:l.attrValues)||a)[t];return o&&o.length?{from:p,to:e.pos+('"'==n.sliceString(e.pos,e.pos+1)?1:0),options:o,validFor:/^"[^"]*"?$/}:null}if("tag"==s){let t=elementName(n,u),l=i[t],a=[],m=u&&u.lastChild;!t||m&&"CloseTag"==m.name&&tagName(n,m)==t||a.push(l?l.closeCompletion:{label:"</"+t+">",type:"type",boost:2});let s=a.concat(((null==l?void 0:l.children)||(u?o:r)).map((e=>e.openCompletion)));if(u&&(null==l?void 0:l.text.length)){let t=u.firstChild;t.to>e.pos-20&&!/\S/.test(e.state.sliceDoc(t.to,e.pos))&&(s=s.concat(l.text))}return{from:p,options:s,validFor:/^<\/?[:\-\.\w\u00b7-\uffff]*$/}}return null}}const xmlLanguage=LRLanguage.define({name:"xml",parser:parser.configure({props:[indentNodeProp.add({Element(e){let t=/^\s*<\//.test(e.textAfter);return e.lineIndent(e.node.from)+(t?0:e.unit)},"OpenTag CloseTag SelfClosingTag":e=>e.column(e.node.from)+e.unit}),foldNodeProp.add({Element(e){let t=e.firstChild,n=e.lastChild;return t&&"OpenTag"==t.name?{from:t.to,to:"CloseTag"==n.name?n.from:e.to}:null}}),bracketMatchingHandle.add({"OpenTag CloseTag":e=>e.getChild("TagName")})]}),languageData:{commentTokens:{block:{open:"\x3c!--",close:"--\x3e"}},indentOnInput:/^\s*<\/$/}});function xml(e={}){return new LanguageSupport(xmlLanguage,xmlLanguage.data.of({autocomplete:completeFromSchema(e.elements||[],e.attributes||[])}))}export{completeFromSchema,xml,xmlLanguage}; |