diff --git a/src/config/langages.js b/src/config/langages.js new file mode 100644 index 0000000..9fceba8 --- /dev/null +++ b/src/config/langages.js @@ -0,0 +1,25 @@ +module.exports = [ + "python", + "c", + "c++", + "c#", + "javascript", + "java", + "haskell", + "smalltalk", + "coffescript", + "css", + "d", + "go", + "haskell", + "html", + "json", + "lua", + "php", + "r", + "ruby", + "scheme", + "shell", + "sql", + 'oz', +]; diff --git a/src/db/MongoDB.js b/src/db/MongoDB.js index 806f2ef..88c963e 100644 --- a/src/db/MongoDB.js +++ b/src/db/MongoDB.js @@ -1,6 +1,7 @@ const { MongoClient, ObjectID } = require("mongodb"); var crypto = require('crypto'); const { nanoid } = require('nanoid'); +const languages = require('../config/langages'); const configs = require('../config/config'); const utils = require('../utils'); @@ -12,7 +13,6 @@ const baseCode = [ {uuid: utils.uuid(Math.random().toString(), 10), content: ' main(\'Hello World !\')'} ]; - class MongoDB { constructor (url) { this.client = new MongoClient(url, { @@ -35,7 +35,7 @@ class MongoDB { } } - async createDocument (language) { + async createDocument (documentLanguage) { let doc = { content: baseCode, creationDate: Date.now(), @@ -45,7 +45,7 @@ class MongoDB { editors: [], documentLink: '', linkView: '', - language: language, + language: documentLanguage, tab: 4 }; try { @@ -173,7 +173,7 @@ class MongoDB { } async changeLanguage(documentLink, newLanguage) { - if (["python"].includes(newLanguage)) { + if (languages.includes(newLanguage)) { return this.changeParam(documentLink, 'language', newLanguage); } } diff --git a/src/publics/css/base.less b/src/publics/css/base.less index 098cce3..13f5bfa 100644 --- a/src/publics/css/base.less +++ b/src/publics/css/base.less @@ -2,7 +2,7 @@ | Generic | \*******************/ -@background-color: #222; +@background-color: #222222; @color: #fff; @font: sans-serif; @absolute-color: #d5e6ed; diff --git a/src/publics/css/editor.less b/src/publics/css/editor.less index bcdfdf5..8ab332e 100644 --- a/src/publics/css/editor.less +++ b/src/publics/css/editor.less @@ -1,3 +1,7 @@ +@background-color: #222222; +@color: #fff; +@header-height: 60px; + /******************\ | Header | \******************/ @@ -57,3 +61,56 @@ section#editor{ background-color: red; border-radius: 10px; } + +/*******************\ +| Navigation Bar | +\*******************/ + +#customise{ + position: fixed; + top: 1.1 * @header-height; + right: 0; + width: 20%; + height: 100%; + max-width: 300px; + min-width: 200px; + padding: 20px; + background-color: darken(@background-color, 2%); + border-left: 1px solid #111111; + z-index: 5; + + ul{ + list-style: none; + + li{ + padding-bottom: 20px; + + h3{ + padding: 5px 0; + color: darken(@color, 50%); + letter-spacing: 3px; + border-bottom: 1px solid lighten(@background-color, 10%); + display: inline; + } + + > :not(h3){ + padding: 7px; + margin-top: 20px; + border-radius: 10px; + } + + select, + input{ + color: @color; + background-color: lighten(@background-color, 5%); + border-color: @background-color; + width: 90%; + } + + #qrcode{ + background-color: white; + display: inline-block; + } + } + } +} diff --git a/src/publics/js/dev/component/custom.js b/src/publics/js/dev/component/custom.js index cd2af38..15932fb 100644 --- a/src/publics/js/dev/component/custom.js +++ b/src/publics/js/dev/component/custom.js @@ -1,3 +1,62 @@ /** - * Tab customization (allow convert current file) + * Tab customization */ + +import {editor, socket} from "/js/dev/page/editor.js"; +import {patterns} from "/js/dev/page/editor/prism/patterns.js"; +import PrismCustom from "/js/dev/page/editor/prism/prismCustom.js"; + +export default class Customize{ + /** Init the customize object + * @param {Editable} editable + */ + constructor(editable) { + this.editable = editable; + + document.getElementById('option-language').addEventListener('change', e => { + language = e.target.value.toLowerCase(); + this.editable.updateAllHighlighting(); + socket.send('language', {language}); + }); + + document.addEventListener('socket.receive.language', e => { + if(Object.keys(patterns).includes(e.detail.language.toLowerCase())){ + language = e.detail.language.toLowerCase(); + document.getElementById('option-language').value = language; + this.editable.updateAllHighlighting(); + } + }); + + for(const lang of Object.keys(patterns)){ + const option = document.createElement('option'); + option.innerText = lang; + if(lang === language) option.selected = true; + document.getElementById('option-language').appendChild(option); + } + + document.getElementById('option-space-size').addEventListener('change', e => { + editor.tab.setSize(e.target.value); + + for(const child of this.editable.editable.children){ + child.innerText = editor.tab.updateText(child.innerText); + new PrismCustom(child, language).apply(); + } + + socket.send('changeTabSize', {size: e.target.value}); + }); + + document.getElementById('option-space-size').value = this.editable.tab.size; + + document.addEventListener('socket.receive.changeTabSize', e => { + if(e.detail.size && Number.isInteger(parseInt(e.detail.size))){ + editor.tab.setSize(e.detail.size); + document.getElementById('option-space-size').value = e.detail.size; + + for(const child of this.editable.editable.children){ + child.innerText = editor.tab.updateText(child.innerText); + new PrismCustom(child, language).apply(); + } + } + }); + } +} diff --git a/src/publics/js/dev/lib/qrcode.min.js b/src/publics/js/dev/lib/qrcode.min.js new file mode 100644 index 0000000..1911078 --- /dev/null +++ b/src/publics/js/dev/lib/qrcode.min.js @@ -0,0 +1,11 @@ +/** + * @fileoverview + * - Using the 'QRCode for Javascript library' + * - Fixed dataset of 'QRCode for Javascript library' for support full-spec. + * - this library has no dependencies. + * + * @author davidshimjs + * @see http://www.d-project.com/ + * @see http://jeromeetienne.github.com/jquery-qrcode/ + */ +var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j=0?p.get(q):0}}for(var r=0,m=0;mm;m++)for(var j=0;jm;m++)for(var j=0;j=0;)b^=f.G15<=0;)b^=f.G18<>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;cf;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=[''],h=0;d>h;h++){g.push("");for(var i=0;d>i;i++)g.push('');g.push("")}g.push("
"),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}(); diff --git a/src/publics/js/dev/page/editor.js b/src/publics/js/dev/page/editor.js index 174bebd..29d91bf 100644 --- a/src/publics/js/dev/page/editor.js +++ b/src/publics/js/dev/page/editor.js @@ -5,9 +5,11 @@ * @date Last modification on 16/11/2020 * @version 1.0.1 */ +import Customize from "/js/dev/component/custom.js"; import Cursor from "/js/dev/page/editor/cursor.js"; import download from "/js/dev/page/editor/download.js"; import Editable from "/js/dev/page/editor/editable.js"; +import {patterns} from "/js/dev/page/editor/prism/patterns.js"; import PrismCustom from "/js/dev/page/editor/prism/prismCustom.js"; import EditorSocket from "/js/dev/page/editor/socket.js"; import _ from "/js/dev/utils/element.js"; @@ -16,8 +18,12 @@ export const socket = new EditorSocket(doc_id); export const editor = new Editable(_.id('editor')); export const cursor = new Cursor(_.id('editor')); +download(_.id('download'), _.id('editor')); + +if(!Object.keys(patterns).includes(language)) language = 'generic'; + for(const child of _.id('editor').children){ - new PrismCustom(child, 'python').ApplyWithCaret(); + new PrismCustom(child, language).apply(); } -download(_.id('download'), _.id('editor')); +export const customize = new Customize(editor); diff --git a/src/publics/js/dev/page/editor/editable.js b/src/publics/js/dev/page/editor/editable.js index 36778ea..fa6e294 100644 --- a/src/publics/js/dev/page/editor/editable.js +++ b/src/publics/js/dev/page/editor/editable.js @@ -19,9 +19,9 @@ import Random from "/js/dev/utils/random.js"; import {insertInText} from "/js/dev/utils/string.js"; export default class Editable{ - constructor(element) { + constructor(element, tabSize=initial_size) { this.editable = element; - this.tab = new Tab(element, TabType.SPACES, 4); + this.tab = Number.isInteger(tabSize) ? new Tab(element, TabType.SPACES, tabSize) : 4; this.linesManager = new LinesManager(element); this.last_request = {}; @@ -79,7 +79,7 @@ export default class Editable{ } break; default: - if(!e.ctrlKey && !e.altKey) PrismCustom.onCurrent('python').ApplyWithCaret(); + if(!e.ctrlKey && !e.altKey) PrismCustom.onCurrent(language).ApplyWithCaret(); } this.linesManager.change = true; }); @@ -223,7 +223,7 @@ export default class Editable{ ) ); document.getSelection().collapseToEnd(); - PrismCustom.onCurrent('python').ApplyWithCaret(); + PrismCustom.onCurrent(language).ApplyWithCaret(); } /** @@ -234,7 +234,7 @@ export default class Editable{ const currentElement = getNodeFromAttribute('uuid'); currentElement.innerHTML = insertInText(currentElement.innerText, lines[0], Caret.getBeginPosition(currentElement)); - PrismCustom.onCurrent('python').apply(); + PrismCustom.onCurrent(language).apply(); let currentUuid = currentElement.getAttribute('uuid'); for(let i=1;i
', '
'); line.remove(); Caret.setPosition(previousSibling, len); } @@ -302,4 +302,16 @@ export default class Editable{ } return requests; } + + /** + * Update all syntax highlighting + */ + updateAllHighlighting(){ + const current = getNodeFromAttribute('uuid') + for(const child of this.editable.children){ + if(current === child) new PrismCustom(child, language).ApplyWithCaret(); + else new PrismCustom(child, language).apply(); + + } + } } diff --git a/src/publics/js/dev/page/editor/linesManager.js b/src/publics/js/dev/page/editor/linesManager.js index 62b7045..fd36446 100644 --- a/src/publics/js/dev/page/editor/linesManager.js +++ b/src/publics/js/dev/page/editor/linesManager.js @@ -67,7 +67,7 @@ export default class LinesManager{ let element = this.select(uuid); if(element){ element.innerText = htmlEncode(content); - new PrismCustom(element, 'python').apply(); + new PrismCustom(element, language).apply(); }else{ Debug.warn(`Error when trying to update element with uuid '${uuid}': No div has this uuid.`) } diff --git a/src/publics/js/dev/page/editor/prism/patterns.js b/src/publics/js/dev/page/editor/prism/patterns.js index 85018bc..6b60f3c 100644 --- a/src/publics/js/dev/page/editor/prism/patterns.js +++ b/src/publics/js/dev/page/editor/prism/patterns.js @@ -1,3 +1,7 @@ +// Those regex are based on https://github.com/ccampbell/rainbow/tree/master/src/language made by Craig Campbell +// Big love to them <3 +// For oz it's base on vscode extension : https://github.com/mozart/vscode-oz/blob/master/syntaxes/oz.tmLanguage.json + export const patterns = { generic: [ { @@ -135,5 +139,1651 @@ export const patterns = { name: 'comment.docstring', pattern: /('{3}|"{3})[\s\S]*?\1/gm } - ] -}; \ No newline at end of file + ], + javascript: [ + + /** + * matches $. or $( + */ + { + name: 'selector', + pattern: /\$(?=\.|\()/g + }, + { + name: 'support', + pattern: /\b(window|document)\b/g + }, + { + name: 'keyword', + pattern: /\b(export|default|from)\b/g + }, + { + name: 'function.call', + pattern: /\b(then)(?=\()/g + }, + { + name: 'variable.language.this', + pattern: /\bthis\b/g + }, + { + name: 'variable.language.super', + pattern: /super(?=\.|\()/g + }, + { + name: 'storage.type', + pattern: /\b(const|let|var)(?=\s)/g + }, + { + matches: { + 1: 'support.property' + }, + pattern: /\.(length|node(Name|Value))\b/g + }, + { + matches: { + 1: 'support.function' + }, + pattern: /(setTimeout|setInterval)(?=\()/g + }, + { + matches: { + 1: 'support.method' + }, + pattern: /\.(getAttribute|replace|push|getElementById|getElementsByClassName|setTimeout|setInterval)(?=\()/g + }, + + /** + * matches any escaped characters inside of a js regex pattern + * + * @see https://github.com/ccampbell/rainbow/issues/22 + * + * this was causing single line comments to fail so it now makes sure + * the opening / is not directly followed by a * + * + * The body of the regex to match a regex was borrowed from: + * http://stackoverflow.com/a/17843773/421333 + */ + { + name: 'string.regexp', + matches: { + 1: 'string.regexp.open', + 2: { + name: 'constant.regexp.escape', + pattern: /\\(.){1}/g + }, + 3: 'string.regexp.close', + 4: 'string.regexp.modifier' + }, + pattern: /(\/)((?![*+?])(?:[^\r\n\[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*\])+)(\/)(?!\/)([igm]{0,3})/g + }, + + /** + * matches runtime function declarations + */ + { + matches: { + 1: 'storage.type', + 3: 'entity.function' + }, + pattern: /(var)?(\s|^)(\S+)(?=\s?=\s?function\()/g + }, + + /** + * matches constructor call + */ + { + matches: { + 1: 'keyword', + 2: 'variable.type' + }, + pattern: /(new)\s+(?!Promise)([^\(]*)(?=\()/g + }, + + /** + * matches any function call in the style functionName: function() + */ + { + name: 'entity.function', + pattern: /(\w+)(?=:\s{0,}function)/g + }, + { + name: 'constant.other', + pattern: /\*(?= as)/g + }, + { + matches: { + 1: 'keyword', + 2: 'constant.other' + }, + pattern: /(export)\s+(\*)/g + }, + { + matches: { + 1: 'storage.type.accessor', + 2: 'entity.name.function' + }, + pattern: /(get|set)\s+(\w+)(?=\()/g + }, + { + matches: { + 2: 'entity.name.function' + }, + pattern: /(^\s*)(\w+)(?=\([^\)]*?\)\s*\{)/gm + }, + { + matches: { + 1: 'storage.type.class', + 2: 'entity.name.class', + 3: 'storage.modifier.extends', + 4: 'entity.other.inherited-class' + }, + pattern: /(class)\s+(\w+)(?:\s+(extends)\s+(\w+))?(?=\s*\{)/g + }, + { + name: 'storage.type.function.arrow', + pattern: /=>/g + }, + { + name: 'support.class.promise', + pattern: /\bPromise(?=(\(|\.))/g + } + ], + java: [ + { + name: "constant", + pattern: /\b(false|null|true|[A-Z_]+)\b/g + }, + { + matches: { + 1: "keyword", + 2: "support.namespace" + }, + pattern: /(import|package)\s(.+)/g + }, + { + // see http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html + name: "keyword", + pattern: /\b(abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|native|new|package|private|protected|public|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|transient|try|void|volatile|while)\b/g + }, + { + name: "string", + pattern: /(".*?")/g + }, + { + name: "char", + pattern: /(')(.|\\.|\\u[\dA-Fa-f]{4})\1/g + }, + { + name: "integer", + pattern: /\b(0x[\da-f]+|\d+)L?\b/g + }, + { + name: "comment", + pattern: /\/\*[\s\S]*?\*\/|(\/\/).*?$/gm + }, + { + name: "support.annotation", + pattern: /@\w+/g + }, + { + matches: { + 1: "entity.function" + }, + pattern: /([^@\.\s]+)\(/g + }, + { + name: "entity.class", + pattern: /\b([A-Z]\w*)\b/g + }, + { + // see http://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html + name: "operator", + pattern: /(\+{1,2}|-{1,2}|~|!|\*|\/|%|(?:<){1,2}|(?:>){1,3}|instanceof|(?:&){1,2}|\^|\|{1,2}|\?|:|(?:=|!|\+|-|\*|\/|%|\^|\||(?:<){1,2}|(?:>){1,3})?=)/g + } + ], + c: [ + { + name: 'meta.preprocessor', + matches: { + 1: [ + { + matches: { + 1: 'keyword.define', + 2: 'entity.name' + }, + pattern: /(\w+)\s(\w+)\b/g + }, + { + name: 'keyword.define', + pattern: /endif/g + }, + { + name: 'constant.numeric', + pattern: /\d+/g + }, + { + matches: { + 1: 'keyword.include', + 2: 'string' + }, + pattern: /(include)\s(.*?)$/g + } + ] + }, + pattern: /\#([\S\s]*?)$/gm + }, + { + name: 'keyword', + pattern: /\b(do|goto|typedef)\b/g + }, + { + name: 'entity.label', + pattern: /\w+:/g + }, + { + matches: { + 1: 'storage.type', + 3: 'storage.type', + 4: 'entity.name.function' + }, + pattern: /\b((un)?signed|const)? ?(void|char|short|int|long|float|double)\*? +((\w+)(?= ?\())?/g + }, + { + matches: { + 2: 'entity.name.function' + }, + pattern: /(\w|\*) +((\w+)(?= ?\())/g + }, + { + name: 'storage.modifier', + pattern: /\b(static|extern|auto|register|volatile|inline)\b/g + }, + { + name: 'support.type', + pattern: /\b(struct|union|enum)\b/g + } + ], + coffescript: [ + { + name: 'comment.block', + pattern: /(\#{3})[\s\S]*\1/gm + }, + { + name: 'string.block', + pattern: /('{3}|"{3})[\s\S]*\1/gm + }, + + /** + * multiline regex with comments + */ + { + name: 'string.regex', + matches: { + 2: { + name: 'comment', + pattern: /\#(.*?)(?=\n)/g + } + }, + pattern: /(\/{3})([\s\S]*)\1/gm + }, + { + matches: { + 1: 'keyword' + }, + pattern: /\b(in|when|is|isnt|of|not|unless|until|super)(?=\b)/gi + }, + { + name: 'keyword.operator', + pattern: /\?/g + }, + { + name: 'constant.language', + pattern: /\b(undefined|yes|on|no|off)\b/g + }, + { + name: 'keyword.variable.coffee', + pattern: /@(\w+)/gi + }, + + /** + * reset global keywards from generic + */ + { + name: 'reset', + pattern: /object|class|print/gi + }, + + /** + * named function + */ + { + 'matches' : { + 1: 'entity.name.function', + 2: 'keyword.operator', + 3: { + name: 'function.argument.coffee', + pattern: /([\@\w]+)/g + }, + 4: 'keyword.function' + }, + pattern: /(\w+)\s{0,}(=|:)\s{0,}\((.*?)((-|=)>)/gi + }, + + /** + * anonymous function + */ + { + matches: { + 1: { + name: 'function.argument.coffee', + pattern: /([\@\w]+)/g + }, + 2: 'keyword.function' + }, + pattern: /\s\((.*?)\)\s{0,}((-|=)>)/gi + }, + + /** + * direct function no arguments + */ + { + 'matches' : { + 1: 'entity.name.function', + 2: 'keyword.operator', + 3: 'keyword.function' + }, + pattern: /(\w+)\s{0,}(=|:)\s{0,}((-|=)>)/gi + }, + + /** + * class definitions + */ + { + matches: { + 1: 'storage.class', + 2: 'entity.name.class', + 3: 'storage.modifier.extends', + 4: 'entity.other.inherited-class' + }, + pattern: /\b(class)\s(\w+)(\sextends\s)?([\w\\]*)?\b/g + }, + + /** + * object instantiation + */ + { + matches: { + 1: 'keyword.new', + 2: { + name: 'support.class', + pattern: /\w+/g + } + }, + pattern: /\b(new)\s(.*?)(?=\s)/g + } + ], + 'c#': [ + { + // @see http://msdn.microsoft.com/en-us/library/23954zh5.aspx + name: 'constant', + pattern: /\b(false|null|true)\b/g + }, + { + // @see http://msdn.microsoft.com/en-us/library/x53a06bb%28v=vs.100%29.aspx + // Does not support putting an @ in front of a keyword which makes it not a keyword anymore. + name: 'keyword', + pattern: /\b(abstract|add|alias|ascending|as|async|await|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|descending|double|do|dynamic|else|enum|event|explicit|extern|false|finally|fixed|float|foreach|for|from|get|global|goto|group|if|implicit|int|interface|internal|into|in|is|join|let|lock|long|namespace|new|object|operator|orderby|out|override|params|partial|private|protected|public|readonly|ref|remove|return|sbyte|sealed|select|set|short|sizeof|stackalloc|static|string|struct|switch|this|throw|try|typeof|uint|unchecked|ulong|unsafe|ushort|using|value|var|virtual|void|volatile|where|while|yield)\b/g + }, + { + matches: { + 1: 'keyword', + 2: { + name: 'support.class', + pattern: /\w+/g + } + }, + pattern: /(typeof)\s([^\$].*?)(\)|;)/g + }, + { + matches: { + 1: 'keyword.namespace', + 2: { + name: 'support.namespace', + pattern: /\w+/g + } + }, + pattern: /\b(namespace)\s(.*?);/g + }, + { + matches: { + 1: 'storage.modifier', + 2: 'storage.class', + 3: 'entity.name.class', + 4: 'storage.modifier.extends', + 5: 'entity.other.inherited-class' + }, + pattern: /\b(abstract|sealed)?\s?(class)\s(\w+)(\sextends\s)?([\w\\]*)?\s?\{?(\n|\})/g + }, + { + name: 'keyword.static', + pattern: /\b(static)\b/g + }, + { + matches: { + 1: 'keyword.new', + 2: { + name: 'support.class', + pattern: /\w+/g + } + + }, + pattern: /\b(new)\s([^\$].*?)(?=\)|\(|;|&)/g + }, + { + name: 'string', + pattern: /(")(.*?)\1/g + }, + { + name: 'integer', + pattern: /\b(0x[\da-f]+|\d+)\b/g + }, + { + name: 'comment', + pattern: /\/\*[\s\S]*?\*\/|(\/\/)[\s\S]*?$/gm + }, + { + name: 'operator', + // @see http://msdn.microsoft.com/en-us/library/6a71f45d%28v=vs.100%29.aspx + // ++ += + -- -= - <<= << <= => >>= >> >= != ! ~ ^ || && &= & ?? :: : *= * |= %= |= == = + pattern: /(\+\+|\+=|\+|--|-=|-|<<=|<<|<=|=>|>>=|>>|>=|!=|!|~|\^|\|\||&&|&=|&|\?\?|::|:|\*=|\*|\/=|%=|\|=|==|=)/g + }, + { + // @see http://msdn.microsoft.com/en-us/library/ed8yd1ha%28v=vs.100%29.aspx + name: 'preprocessor', + pattern: /(\#if|\#else|\#elif|\#endif|\#define|\#undef|\#warning|\#error|\#line|\#region|\#endregion|\#pragma)[\s\S]*?$/gm + } + ], + css: [ + { + name: 'comment', + pattern: /\/\*[\s\S]*?\*\//gm + }, + { + name: 'constant.hex-color', + pattern: /#([a-f0-9]{3}|[a-f0-9]{6})(?=;|\s|,|\))/gi + }, + { + matches: { + 1: 'constant.numeric', + 2: 'keyword.unit' + }, + pattern: /(\d+)(px|em|cm|s|%)?/g + }, + { + name: 'string', + pattern: /('|")(.*?)\1/g + }, + { + name: 'support.css-property', + matches: { + 1: 'support.vendor-prefix' + }, + pattern: /(-o-|-moz-|-webkit-|-ms-)?[\w-]+(?=\s?:)(?!.*\{)/g + }, + { + matches: { + 1: [ + { + name: 'entity.name.sass', + pattern: /&/g + }, + { + name: 'direct-descendant', + pattern: />/g + }, + { + name: 'entity.name.class', + pattern: /\.[\w\-_]+/g + }, + { + name: 'entity.name.id', + pattern: /\#[\w\-_]+/g + }, + { + name: 'entity.name.pseudo', + pattern: /:[\w\-_]+/g + }, + { + name: 'entity.name.tag', + pattern: /\w+/g + } + ] + }, + pattern: /([\w\ ,\n:\.\#\&\;\-_]+)(?=.*\{)/g + }, + { + matches: { + 2: 'support.vendor-prefix', + 3: 'support.css-value' + }, + pattern: /(:|,)\s*(-o-|-moz-|-webkit-|-ms-)?([a-zA-Z-]*)(?=\b)(?!.*\{)/g + } + ], + go: [ + { + matches: { + 1: [ + { + name: 'keyword.operator', + pattern: /\=|\+/g + } + ], + 2: { + name: 'string', + matches: { + name: 'constant.character.escape', + pattern: /\\(`|"){1}/g + } + } + }, + pattern: /(\(|\s|\[|\=|:|\+|\{|,)((`|")([^\\\1]|\\.)*?(\3))/gm + }, + { + name: 'comment', + pattern: /\/\*[\s\S]*?\*\/|(\/\/)(?!.*(`|").*?\1).*?$/gm + }, + { + matches: { + 1: 'keyword' + }, + pattern: /\b(d(efault|efer)|fallthrough|go(to)?|range|select)(?=\b)/gi + }, + { + name: 'keyword', + pattern: /\bpackage(?=\s*\w)/gi + }, + { + matches: { + 1: 'storage.type', + 2: 'entity.name.struct' + }, + pattern: /\b(type)\s+(\w+)\b(?=\s+struct\b)/gi + }, + { + matches: { + 1: 'storage.type', + 2: 'entity.name.type' + }, + pattern: /\b(type)\s+(\w+)\b/gi + }, + { + name: 'storage.type', + pattern: /\b(bool|byte|complex(64|128)|float(32|64)|func|interface|map|rune|string|struct|u?int(8|16|32|64)?|var)(?=\b)/g + }, + { + name: 'keyword.operator.initialize', + pattern: /\:=/g + }, + { + matches: { + 1: 'storage.function', + 2: 'entity.name.function' + }, + pattern: /(func)\s+(?:\(.*?\))\s+(.*?)(?=\()/g + }, + { + matches: { + 1: 'storage.function', + 2: 'entity.name.function' + }, + pattern: /(func)\s+(.*?)(?=\()/g + } + ], + html : [ + { + name: 'source.php.embedded', + matches: { + 1: 'variable.language.php-tag', + 2: { + language: 'php' + }, + 3: 'variable.language.php-tag' + }, + pattern: /(<\?php|<\?=?(?!xml))([\s\S]*?)(\?>)/gm + }, + { + name: 'source.css.embedded', + matches: { + 1: { + matches: { + 1: 'support.tag.style', + 2: [ + { + name: 'entity.tag.style', + pattern: /^style/g + }, + { + name: 'string', + pattern: /('|")(.*?)(\1)/g + }, + { + name: 'entity.tag.style.attribute', + pattern: /(\w+)/g + } + ], + 3: 'support.tag.style' + }, + pattern: /(<\/?)(style.*?)(>)/g + }, + 2: { + language: 'css' + }, + 3: 'support.tag.style', + 4: 'entity.tag.style', + 5: 'support.tag.style' + }, + pattern: /(<style.*?>)([\s\S]*?)(<\/)(style)(>)/gm + }, + { + name: 'source.js.embedded', + matches: { + 1: { + matches: { + 1: 'support.tag.script', + 2: [ + { + name: 'entity.tag.script', + pattern: /^script/g + }, + + { + name: 'string', + pattern: /('|")(.*?)(\1)/g + }, + { + name: 'entity.tag.script.attribute', + pattern: /(\w+)/g + } + ], + 3: 'support.tag.script' + }, + pattern: /(<\/?)(script.*?)(>)/g + }, + 2: { + language: 'javascript' + }, + 3: 'support.tag.script', + 4: 'entity.tag.script', + 5: 'support.tag.script' + }, + pattern: /(<script(?! src).*?>)([\s\S]*?)(<\/)(script)(>)/gm + }, + { + name: 'comment.html', + pattern: /<\!--[\S\s]*?-->/g + }, + { + matches: { + 1: 'support.tag.open', + 2: 'support.tag.close' + }, + pattern: /(<)|(\/?\??>)/g + }, + { + name: 'support.tag', + matches: { + 1: 'support.tag', + 2: 'support.tag.special', + 3: 'support.tag-name' + }, + pattern: /(<\??)(\/|\!?)(\w+)/g + }, + { + matches: { + 1: 'support.attribute' + }, + pattern: /([a-z-]+)(?=\=)/gi + }, + { + matches: { + 1: 'support.operator', + 2: 'string.quote', + 3: 'string.value', + 4: 'string.quote' + }, + pattern: /(=)('|")(.*?)(\2)/g + }, + { + matches: { + 1: 'support.operator', + 2: 'support.value' + }, + pattern: /(=)([a-zA-Z\-0-9]*)\b/g + }, + { + matches: { + 1: 'support.attribute' + }, + pattern: /\s([\w-]+)(?=\s|>)(?![\s\S]*<)/g + } + ], + json : [ + { + matches: { + 0: { + name: 'string', + matches: { + name: 'constant.character.escape', + pattern: /\\('|"){1}/g + } + } + }, + pattern: /(\"|\')(\\?.)*?\1/g + }, + { + name: 'constant.numeric', + pattern: /\b(-?(0x)?\d*\.?[\da-f]+|NaN|-?Infinity)\b/gi + }, + { + name: 'constant.language', + pattern: /\b(true|false|null)\b/g + } + ], + lua: [ + { + matches: { + 1: { + name: 'keyword.operator', + pattern: /\=/g + }, + 2: { + name: 'string', + matches: { + name: 'constant.character.escape', + pattern: /\\('|"){1}/g + } + } + }, + pattern: /(\(|\s|\[|\=)(('|")([^\\\1]|\\.)*?(\3))/gm + }, + { + name: 'comment', + pattern: /\-{2}\[{2}\-{2}[\s\S]*?\-{2}\]{2}\-{2}|(\-{2})[\s\S]*?$/gm + }, + { + name: 'constant.numeric', + pattern: /\b(\d+(\.\d+)?(e(\+|\-)?\d+)?(f|d)?|0x[\da-f]+)\b/gi + }, + { + matches: { + 1: 'keyword' + }, + pattern: /\b((a|e)nd|in|repeat|break|local|return|do|for|then|else(if)?|function|not|if|or|until|while)(?=\b)/gi + }, + { + name: 'constant.language', + pattern: /true|false|nil/g + }, + { + name: 'keyword.operator', + pattern: /\+|\!|\-|&(gt|lt|amp);|\||\*|\=|#|\.{2}/g + }, + { + matches: { + 1: 'storage.function', + 2: 'entity.name.function' + }, + pattern: /(function)\s+(\w+[\:|\.]?\w+?)(?=\()/g + }, + { + matches: { + 1: 'support.function' + }, + pattern: /\b(print|require|module|\w+\.\w+)(?=\()/g + } + ], + php: [ + { + name: 'support', + pattern: /\becho\b/ig + }, + { + matches: { + 1: 'variable.dollar-sign', + 2: 'variable' + }, + pattern: /(\$)(\w+)\b/g + }, + { + name: 'constant.language', + pattern: /true|false|null/ig + }, + { + name: 'constant', + pattern: /\b[A-Z0-9_]{2,}\b/g + }, + { + name: 'keyword.dot', + pattern: /\./g + }, + { + name: 'keyword', + pattern: /\b(die|end(for(each)?|switch|if)|case|require(_once)?|include(_once)?)(?=\b)/ig + }, + { + matches: { + 1: 'keyword', + 2: { + name: 'support.class', + pattern: /\w+/g + } + }, + pattern: /(instanceof)\s([^\$].*?)(\)|;)/ig + }, + + /** + * these are the top 50 most used PHP functions + * found from running a script and checking the frequency of each function + * over a bunch of popular PHP frameworks then combining the results + */ + { + matches: { + 1: 'support.function' + }, + pattern: /\b(array(_key_exists|_merge|_keys|_shift)?|isset|count|empty|unset|printf|is_(array|string|numeric|object)|sprintf|each|date|time|substr|pos|str(len|pos|tolower|_replace|totime)?|ord|trim|in_array|implode|end|preg_match|explode|fmod|define|link|list|get_class|serialize|file|sort|mail|dir|idate|log|intval|header|chr|function_exists|dirname|preg_replace|file_exists)(?=\()/ig + }, + { + name: 'variable.language.php-tag', + pattern: /(<\?(php)?|\?>)/ig + }, + { + matches: { + 1: 'keyword.namespace', + 2: { + name: 'support.namespace', + pattern: /\w+/g + } + }, + pattern: /\b(namespace|use)\s(.*?);/ig + }, + { + matches: { + 1: 'storage.modifier', + 2: 'storage.class', + 3: 'entity.name.class', + 4: 'storage.modifier.extends', + 5: 'entity.other.inherited-class', + 6: 'storage.modifier.extends', + 7: 'entity.other.inherited-class' + }, + pattern: /\b(abstract|final)?\s?(class|interface|trait)\s(\w+)(\sextends\s)?([\w\\]*)?(\simplements\s)?([\w\\]*)?\s?\{?(\n|\})/ig + }, + { + name: 'keyword.static', + pattern: /self::|static::/ig + }, + { + matches: { + 1: 'storage.function', + 2: 'entity.name.function.magic' + }, + pattern: /(function)\s(__.*?)(?=\()/ig + }, + { + matches: { + 1: 'storage.function', + 2: 'entity.name.function' + }, + pattern: /(function)\s(.*?)(?=\()/ig + }, + { + matches: { + 1: 'keyword.new', + 2: { + name: 'support.class', + pattern: /\w+/g + } + }, + pattern: /\b(new)\s([^\$][a-z0-9_\\]*?)(?=\)|\(|;)/ig + }, + { + matches: { + 1: { + name: 'support.class', + pattern: /\w+/g + }, + 2: 'keyword.static' + }, + pattern: /([\w\\]*?)(::)(?=\b|\$)/g + }, + { + matches: { + 2: { + name: 'support.class', + pattern: /\w+/g + } + }, + pattern: /(\(|,\s?)([\w\\]*?)(?=\s\$)/g + } + ], + ruby: [ + /** + * __END__ DATA + */ + { + matches: { + 1: 'variable.language', + 2: { + language: null + } + }, + //find __END__ and consume remaining text + pattern: /^(__END__)\n((?:.*\n)*)/gm + }, + /** + * Strings + * 1. No support for multi-line strings + */ + { + name: 'string', + matches: { + 1: 'string.open', + 2: [{ + name: 'string.interpolation', + matches: { + 1: 'string.open', + 2: { + language: 'ruby' + }, + 3: 'string.close' + }, + pattern: /(\#\{)(.*?)(\})/g + }], + 3: 'string.close' + }, + pattern: /("|`)(.*?[^\\\1])?(\1)/g + }, + { + name: 'string', + pattern: /('|"|`)([^\\\1\n]|\\.)*?\1/g + }, + { + name: 'string', + pattern: /%[qQ](?=(\(|\[|\{|<|.)(.*?)(?:'|\)|\]|\}|>|\1))(?:\(\2\)|\[\2\]|\{\2\}|\<\2>|\1\2\1)/g + }, + /** + * Heredocs + * Heredocs of the form `<<'HTML' ... HTML` are unsupported. + */ + { + matches: { + 1: 'string', + 2: 'string', + 3: 'string' + }, + pattern: /(<<)(\w+).*?$([\s\S]*?^\2)/gm + }, + { + matches: { + 1: 'string', + 2: 'string', + 3: 'string' + }, + pattern: /(<<\-)(\w+).*?$([\s\S]*?\2)/gm + }, + /** + * Regular expressions + * Escaped delimiter (`/\//`) is unsupported. + */ + { + name: 'string.regexp', + matches: { + 1: 'string.regexp', + 2: { + name: 'string.regexp', + pattern: /\\(.){1}/g + }, + 3: 'string.regexp', + 4: 'string.regexp' + }, + pattern: /(\/)(.*?)(\/)([a-z]*)/g + }, + { + name: 'string.regexp', + matches: { + 1: 'string.regexp', + 2: { + name: 'string.regexp', + pattern: /\\(.){1}/g + }, + 3: 'string.regexp', + 4: 'string.regexp' + }, + pattern: /%r(?=(\(|\[|\{|<|.)(.*?)('|\)|\]|\}|>|\1))(?:\(\2\)|\[\2\]|\{\2\}|\<\2>|\1\2\1)([a-z]*)/g + }, + /** + * Comments + */ + { + name: 'comment', + pattern: /#.*$/gm + }, + { + name: 'comment', + pattern: /^\=begin[\s\S]*?\=end$/gm + }, + /** + * Symbols + */ + { + matches: { + 1: 'constant' + }, + pattern: /(\w+:)[^:]/g + }, + { + matches: { + 1: 'constant.symbol' + }, + pattern: /[^:](:(?:\w+|(?=['"](.*?)['"])(?:"\2"|'\2')))/g + }, + { + name: 'constant.numeric', + pattern: /\b(0x[\da-f]+|[\d_]+)\b/g + }, + { + name: 'support.class', + pattern: /\b[A-Z]\w*(?=((\.|::)[A-Za-z]|\[))/g + }, + { + name: 'constant', + pattern: /\b[A-Z]\w*\b/g + }, + /** + * Keywords, variables, constants, and operators + * In Ruby some keywords are valid method names, e.g., MyClass#yield + * Don't mark those instances as "keywords" + */ + { + matches: { + 1: 'storage.class', + 2: 'entity.name.class', + 3: 'entity.other.inherited-class' + }, + pattern: /\s*(class)\s+((?:(?:::)?[A-Z]\w*)+)(?:\s+<\s+((?:(?:::)?[A-Z]\w*)+))?/g + }, + { + matches: { + 1: 'storage.module', + 2: 'entity.name.class' + }, + pattern: /\s*(module)\s+((?:(?:::)?[A-Z]\w*)+)/g + }, + { + name: 'variable.global', + pattern: /\$([a-zA-Z_]\w*)\b/g + }, + { + name: 'variable.class', + pattern: /@@([a-zA-Z_]\w*)\b/g + }, + { + name: 'variable.instance', + pattern: /@([a-zA-Z_]\w*)\b/g + }, + { + matches: { + 1: 'keyword.control' + }, + pattern: /[^\.]\b(BEGIN|begin|case|class|do|else|elsif|END|end|ensure|for|if|in|module|rescue|then|unless|until|when|while)\b(?![?!])/g + }, + { + matches: { + 1: 'keyword.control.pseudo-method' + }, + pattern: /[^\.]\b(alias|alias_method|break|next|redo|retry|return|super|undef|yield)\b(?![?!])|\bdefined\?|\bblock_given\?/g + }, + { + matches: { + 1: 'constant.language' + }, + pattern: /\b(nil|true|false)\b(?![?!])/g + }, + { + matches: { + 1: 'variable.language' + }, + pattern: /\b(__(FILE|LINE)__|self)\b(?![?!])/g + }, + { + matches: { + 1: 'keyword.special-method' + }, + pattern: /\b(require|gem|initialize|new|loop|include|extend|raise|attr_reader|attr_writer|attr_accessor|attr|catch|throw|private|module_function|public|protected)\b(?![?!])/g + }, + { + name: 'keyword.operator', + pattern: /\s\?\s|=|<<|<<=|%=|&=|\*=|\*\*=|\+=|\-=|\^=|\|{1,2}=|<<|<=>|<(?!<|=)|>(?!<|=|>)|<=|>=|===|==|=~|!=|!~|%|&|\*\*|\*|\+|\-|\/|\||~|>>/g + }, + { + matches: { + 1: 'keyword.operator.logical' + }, + pattern: /[^\.]\b(and|not|or)\b/g + }, + + /** + * Functions + * 1. No support for marking function parameters + */ + { + matches: { + 1: 'storage.function', + 2: 'entity.name.function' + }, + pattern: /(def)\s(.*?)(?=(\s|\())/g + } + ], + sql: [ + { + matches: { + 2: { + name: 'string', + matches: { + name: 'constant.character.escape', + pattern: /\\('|"|`){1}/g + } + } + }, + pattern: /(\(|\s|\[|\=|:|\+|\.|\{|,)(('|"|`)([^\\\1]|\\.)*?(\3))/gm + }, + { + name: 'comment', + pattern: /--.*$|\/\*[\s\S]*?\*\/|(\/\/)[\s\S]*?$/gm + }, + { + name: 'constant.numeric', + pattern: /\b(\d+(\.\d+)?(e(\+|\-)?\d+)?(f|d)?|0x[\da-f]+)\b/gi + }, + { + name: 'function.call', + pattern: /(\w+?)(?=\()/g + }, + { + name: 'keyword', + pattern: /\b(ABSOLUTE|ACTION|ADA|ADD|ALL|ALLOCATE|ALTER|AND|ANY|ARE|AS|ASC|ASSERTION|AT|AUTHORIZATION|AVG|BEGIN|BETWEEN|BIT|BIT_LENGTH|BOTH|BY|CASCADE|CASCADED|CASE|CAST|CATALOG|CHAR|CHARACTER|CHARACTER_LENGTH|CHAR_LENGTH|CHECK|CLOSE|COALESCE|COLLATE|COLLATION|COLUMN|COMMIT|CONNECT|CONNECTION|CONSTRAINT|CONSTRAINTS|CONTINUE|CONVERT|CORRESPONDING|COUNT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATE|DAY|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFERRABLE|DEFERRED|DELETE|DESC|DESCRIBE|DESCRIPTOR|DIAGNOSTICS|DISCONNECT|DISTINCT|DOMAIN|DOUBLE|DROP|ELSE|END|END-EXEC|ESCAPE|EXCEPT|EXCEPTION|EXEC|EXECUTE|EXISTS|EXTERNAL|EXTRACT|FALSE|FETCH|FIRST|FLOAT|FOR|FOREIGN|FORTRAN|FOUND|FROM|FULL|GET|GLOBAL|GO|GOTO|GRANT|GROUP|HAVING|HOUR|IDENTITY|IMMEDIATE|IN|INCLUDE|INDEX|INDICATOR|INITIALLY|INNER|INPUT|INSENSITIVE|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|IS|ISOLATION|JOIN|KEY|LANGUAGE|LAST|LEADING|LEFT|LEVEL|LIKE|LIMIT|LOCAL|LOWER|MATCH|MAX|MIN|MINUTE|MODULE|MONTH|NAMES|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONE|NOT|NULL|NULLIF|NUMERIC|OCTET_LENGTH|OF|ON|ONLY|OPEN|OPTION|OR|ORDER|OUTER|OUTPUT|OVERLAPS|PAD|PARTIAL|PASCAL|POSITION|PRECISION|PREPARE|PRESERVE|PRIMARY|PRIOR|PRIVILEGES|PROCEDURE|PUBLIC|READ|REAL|REFERENCES|RELATIVE|RESTRICT|REVOKE|RIGHT|ROLLBACK|ROWS|SCHEMA|SCROLL|SECOND|SECTION|SELECT|SESSION|SESSION_USER|SET|SIZE|SMALLINT|SOME|SPACE|SQL|SQLCA|SQLCODE|SQLERROR|SQLSTATE|SQLWARNING|SUBSTRING|SUM|SYSTEM_USER|TABLE|TEMPORARY|THEN|TIME|TIMESTAMP|TIMEZONE_HOUR|TIMEZONE_MINUTE|TO|TRAILING|TRANSACTION|TRANSLATE|TRANSLATION|TRIM|TRUE|UNION|UNIQUE|UNKNOWN|UPDATE|UPPER|USAGE|USER|USING|VALUE|VALUES|VARCHAR|VARYING|VIEW|WHEN|WHENEVER|WHERE|WITH|WORK|WRITE|YEAR|ZONE|USE)(?=\b)/gi + }, + { + name: 'keyword.operator', + pattern: /\+|\!|\-|&(gt|lt|amp);|\||\*|=/g + } + ], + scheme: [ + { + /* making peace with HTML */ + name: 'plain', + pattern: />|</g + }, + { + name: 'comment', + pattern: /;.*$/gm + }, + { + name: 'constant.language', + pattern: /#t|#f|'\(\)/g + }, + { + name: 'constant.symbol', + pattern: /'[^()\s#]+/g + }, + { + name: 'constant.number', + pattern: /\b\d+(?:\.\d*)?\b/g + }, + { + name: 'string', + pattern: /".+?"/g + }, + { + matches: { + 1: 'storage.function', + 2: 'variable' + }, + pattern: /\(\s*(define)\s+\(?(\S+)/g + }, + { + matches: { + 1: 'keyword' + }, + pattern: /\(\s*(begin|define\-syntax|if|lambda|quasiquote|quote|set!|syntax\-rules|and|and\-let\*|case|cond|delay|do|else|or|let|let\*|let\-syntax|letrec|letrec\-syntax)(?=[\]()\s#])/g + }, + { + matches: { + 1: 'entity.function' + }, + pattern: /\(\s*(eqv\?|eq\?|equal\?|number\?|complex\?|real\?|rational\?|integer\?|exact\?|inexact\?|=|<|>|<=|>=|zero\?|positive\?|negative\?|odd\?|even\?|max|min|\+|\-|\*|\/|abs|quotient|remainder|modulo|gcd|lcm|numerator|denominator|floor|ceiling|truncate|round|rationalize|exp|log|sin|cos|tan|asin|acos|atan|sqrt|expt|make\-rectangular|make\-polar|real\-part|imag\-part|magnitude|angle|exact\->inexact|inexact\->exact|number\->string|string\->number|not|boolean\?|pair\?|cons|car|cdr|set\-car!|set\-cdr!|caar|cadr|cdar|cddr|caaar|caadr|cadar|caddr|cdaar|cdadr|cddar|cdddr|caaaar|caaadr|caadar|caaddr|cadaar|cadadr|caddar|cadddr|cdaaar|cdaadr|cdadar|cdaddr|cddaar|cddadr|cdddar|cddddr|null\?|list\?|list|length|append|reverse|list\-tail|list\-ref|memq|memv|member|assq|assv|assoc|symbol\?|symbol\->string|string\->symbol|char\?|char=\?|char<\?|char>\?|char<=\?|char>=\?|char\-ci=\?|char\-ci<\?|char\-ci>\?|char\-ci<=\?|char\-ci>=\?|char\-alphabetic\?|char\-numeric\?|char\-whitespace\?|char\-upper\-case\?|char\-lower\-case\?|char\->integer|integer\->char|char\-upcase|char\-downcase|string\?|make\-string|string|string\-length|string\-ref|string\-set!|string=\?|string\-ci=\?|string<\?|string>\?|string<=\?|string>=\?|string\-ci<\?|string\-ci>\?|string\-ci<=\?|string\-ci>=\?|substring|string\-append|string\->list|list\->string|string\-copy|string\-fill!|vector\?|make\-vector|vector|vector\-length|vector\-ref|vector\-set!|vector\->list|list\->vector|vector\-fill!|procedure\?|apply|map|for\-each|force|call\-with\-current\-continuation|call\/cc|values|call\-with\-values|dynamic\-wind|eval|scheme\-report\-environment|null\-environment|interaction\-environment|call\-with\-input\-file|call\-with\-output\-file|input\-port\?|output\-port\?|current\-input\-port|current\-output\-port|with\-input\-from\-file|with\-output\-to\-file|open\-input\-file|open\-output\-file|close\-input\-port|close\-output\-port|read|read\-char|peek\-char|eof\-object\?|char\-ready\?|write|display|newline|write\-char|load|transcript\-on|transcript\-off)(?=[\]()\s#])/g + } + ], + r: [ + /** + * Note that a valid variable name is of the form: + * [.a-zA-Z][0-9a-zA-Z._]* + */ + { + matches: { + 1: { + name: 'keyword.operator', + pattern: /\=|<\-|<-/g + }, + 2: { + name: 'string', + matches: { + name: 'constant.character.escape', + pattern: /\\('|"){1}/g + } + } + }, + pattern: /(\(|\s|\[|\=|:)(('|")([^\\\1]|\\.)*?(\3))/gm + }, + + /** + * Most of these are known via the Language Reference. + * The built-in constant symbols are known via ?Constants. + */ + { + matches: { + 1: 'constant.language' + }, + pattern: /\b(NULL|NA|TRUE|FALSE|T|F|NaN|Inf|NA_integer_|NA_real_|NA_complex_|NA_character_)\b/g + }, + { + matches: { + 1: 'constant.symbol' + }, + pattern: /[^0-9a-zA-Z\._](LETTERS|letters|month\.(abb|name)|pi)/g + }, + + /** + * @todo: The list subsetting operator isn't quite working properly. + * It includes the previous variable when it should only match [[ + */ + { + name: 'keyword.operator', + pattern: /<-|<-|-|==|<=|<=|>>|>=|<|>|&&|&&|&|&|!=|\|\|?|\*|\+|\^|\/|%%|%\/%|\=|%in%|%\*%|%o%|%x%|\$|:|~|\[{1,2}|\]{1,2}/g + }, + { + matches: { + 1: 'storage', + 3: 'entity.function' + }, + pattern: /(\s|^)(.*)(?=\s?=\s?function\s\()/g + }, + { + matches: { + 1: 'storage.function' + }, + pattern: /[^a-zA-Z0-9._](function)(?=\s*\()/g + }, + { + matches: { + 1: 'namespace', + 2: 'keyword.operator', + 3: 'function.call' + }, + pattern: /([a-zA-Z][a-zA-Z0-9._]+)([:]{2,3})([.a-zA-Z][a-zA-Z0-9._]*(?=\s*\())\b/g + }, + + /* + * Note that we would perhaps match more builtin functions and + * variables, but there are so many that most are ommitted for now. + * See ?builtins for more info. + * + * @todo: Fix the case where we have a function like tmp.logical(). + * This should just be a function call, at the moment it's + * only partly a function all. + */ + { + name: 'support.function', + pattern: /(^|[^0-9a-zA-Z\._])(array|character|complex|data\.frame|double|integer|list|logical|matrix|numeric|vector)(?=\s*\()/g + } + ], + haskell: [ + ///- Comments + { + name: 'comment', + pattern: /\{\-\-[\s\S(\w+)]+[\-\-][\}$]/gm + // /\{\-{2}[\s\S(.*)]+[\-\-][\}$]/gm [multiple lines] + }, + { + name: 'comment', + pattern: /\-\-(.*)/g + // /\-\-\s(.+)$/gm [single] + }, + ///- End Comments + + ///- Namespace (module) + { + matches: { + 1: 'keyword', + 2: 'support.namespace' + }, + pattern: /\b(module)\s(\w+)\s[\(]?(\w+)?[\)?]\swhere/g + }, + ///- End Namespace (module) + + ///- Keywords and Operators + { + name: 'keyword.operator', + pattern: /\+|\!|\-|&(gt|lt|amp);|\/\=|\||\@|\:|\.|\+{2}|\:|\*|\=|#|\.{2}|(\\)[a-zA-Z_]/g + }, + { + name: 'keyword', + pattern: /\b(case|class|foreign|hiding|qualified|data|family|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|in|otherwise|module|newtype|of|then|type|where)\b/g + }, + { + name: 'keyword', + pattern: /[\`][a-zA-Z_']*?[\`]/g + }, + ///- End Keywords and Operators + + + ///- Infix|Infixr|Infixl + { + matches: { + 1: 'keyword', + 2: 'keyword.operator' + }, + pattern: /\b(infix|infixr|infixl)+\s\d+\s(\w+)*/g + }, + ///- End Infix|Infixr|Infixl + + { + name: 'entity.class', + pattern: /\b([A-Z][A-Za-z0-9_']*)/g + }, + + // From c.js + { + name: 'meta.preprocessor', + matches: { + 1: [ + { + matches: { + 1: 'keyword.define', + 2: 'entity.name' + }, + pattern: /(\w+)\s(\w+)\b/g + }, + { + name: 'keyword.define', + pattern: /endif/g + }, + { + name: 'constant.numeric', + pattern: /\d+/g + }, + { + matches: { + 1: 'keyword.include', + 2: 'string' + }, + pattern: /(include)\s(.*?)$/g + } + ] + }, + pattern: /^\#([\S\s]*?)$/gm + } + ], + d: [ + { + name: 'constant', + pattern: /\b(false|null|true)\b/gm + }, + { + // http://dlang.org/lex.html + name: 'keyword', + pattern: /\b(abstract|alias|align|asm|assert|auto|body|bool|break|byte|case|cast|catch|cdouble|cent|cfloat|char|class|const|continue|creal|dchar|debug|default|delegate|delete|deprecated|do|double|else|enum|export|extern|final|finally|float|for|foreach|foreach_reverse|function|goto|idouble|if|ifloat|immutable|import|in|inout|int|interface|invariant|ireal|is|lazy|long|macro|mixin|module|new|nothrow|null|out|override|package|pragma|private|protected|public|pure|real|ref|return|scope|shared|short|size_t|static|string|struct|super|switch|synchronized|template|this|throw|try|typedef|typeid|typeof|ubyte|ucent|uint|ulong|union|unittest|ushort|version|void|volatile|wchar|while|with|__FILE__|__LINE__|__gshared|__traits|__vector|__parameters)\b/gm + }, + { + matches: { + 1: 'keyword', + 2: { + name: 'support.class', + pattern: /\w+/gm + } + }, + pattern: /(typeof)\s([^\$].*?)(\)|;)/gm + }, + { + matches: { + 1: 'keyword.namespace', + 2: { + name: 'support.namespace', + pattern: /\w+/gm + } + }, + pattern: /\b(namespace)\s(.*?);/gm + }, + { + matches: { + 1: 'storage.modifier', + 2: 'storage.class', + 3: 'entity.name.class', + 4: 'storage.modifier.extends', + 5: 'entity.other.inherited-class' + }, + pattern: /\b(abstract|sealed)?\s?(class)\s(\w+)(\sextends\s)?([\w\\]*)?\s?\{?(\n|\})/gm + }, + { + name: 'keyword.static', + pattern: /\b(static)\b/gm + }, + { + matches: { + 1: 'keyword.new', + 2: { + name: 'support.class', + pattern: /\w+/gm + } + + }, + pattern: /\b(new)\s([^\$].*?)(?=\)|\(|;|&)/gm + }, + { + name: 'string', + pattern: /("|')(.*?)\1/gm + }, + { + name: 'integer', + pattern: /\b(0x[\da-f]+|\d+)\b/gm + }, + { + name: 'comment', + pattern: /\/\*[\s\S]*?\*\/|\/\+[\s\S]*?\+\/|(\/\/)[\s\S]*?$/gm + }, + { + // http://dlang.org/operatoroverloading.html + name: 'operator', + // / /= &= && & |= || | -= -- - += ++ + <= << < <<= <>= <> > >>>= >>= >= >> >>> != !<>= !<> !<= !< !>= !> ! [ ] $ == = *= * %= % ^^= ^= ^^ ^ ~= ~ @ => : + pattern: /(\/|\/=|&=|&&|&|\|=|\|\|\||\-=|\-\-|\-|\+=|\+\+|\+|<=|<<|<|<<=|<>=|<>|>|>>>=|>>=|>=|>>|>>>|!=|!<>=|!<>|!<=|!<|!>=|!>|!|[|]|\$|==|=|\*=|\*|%=|%|\^\^=|\^=|\^\^|\^|~=|~|@|=>|\:)/gm + } + ], + smalltalk: [ + { + name: 'keyword.pseudovariable', + pattern: /self|thisContext/g + }, + { + name: 'keyword.constant', + pattern: /false|nil|true/g + }, + { + name: 'string', + pattern: /'([^']|'')*'/g + }, + { + name: 'string.symbol', + pattern: /#\w+|#'([^']|'')*'/g + }, + { + name: 'string.character', + pattern: /\$\w+/g + }, + { + name: 'comment', + pattern: /"([^"]|"")*"/g + }, + { + name: 'constant.numeric', + pattern: /-?\d+(\.\d+)?((r-?|s)[A-Za-z0-9]+|e-?[0-9]+)?/g + }, + { + name: 'entity.name.class', + pattern: /\b[A-Z]\w*/g + }, + { + name: 'entity.name.function', + pattern: /\b[a-z]\w*:?/g + }, + { + name: 'entity.name.binary', + pattern: /(<|>|&|[=~\|\\\/!@*\-_+])+/g + }, + { + name: 'operator.delimiter', + pattern: /;[\(\)\[\]\{\}]|#\[|#\(^\./g + } + ], + oz : [ + // https://github.com/mozart/vscode-oz/blob/master/syntaxes/oz.tmLanguage.json + // TODO add missing css + { + name: "operator", + pattern: /(<:|:>|::|&|@|#|_|\[\]|\.\.\.)/g + }, + { + name: "operator.assignment", + pattern: /(\=|\:=)/g + }, + { + name: "operator.comparison", + pattern: /<|=<|==|\=|>=|>/g + }, + { + name: "operator.list", + pattern: /\b\|\b/g + }, + { + name: "constant.numeric", + pattern: /(\d+\.\d+|\d+)/g + }, + { + name: "constant.language", + pattern: /\b(false|true|nil)\b/g + }, + { + name: "variable", + pattern: /[A-Z][0-9A-z]*/g + }, + { + name: "keyword.control", + pattern: /(? b - a); } -/** - * Encodes < and > as html entities - * - * @param {string} code - * @return {string} - */ -function htmlEntities(code) { - return code.replace(//g, '>').replace(/&(?![\w\#]+;)/g, '&'); -} - /** * Determines if two different matches have complete overlap with each other * @@ -250,6 +240,7 @@ export class Prism { regex = _cloneRegex(regex); const match = regex.exec(code); + if (!match) { return false; } @@ -439,4 +430,4 @@ export class Prism { this.refract = _processCodeWithPatterns; } -} \ No newline at end of file +} diff --git a/src/publics/js/dev/page/editor/tab.js b/src/publics/js/dev/page/editor/tab.js index 47719a4..249a1c0 100644 --- a/src/publics/js/dev/page/editor/tab.js +++ b/src/publics/js/dev/page/editor/tab.js @@ -2,8 +2,8 @@ * This module deals with tabs. * @author Brieuc Dubois * @date Created on 15/11/2020 - * @date Last modification on 15/11/2020 - * @version 1.0.0 + * @date Last modification on 27/11/2020 + * @version 1.1.0 */ @@ -26,6 +26,7 @@ export default class Tab{ */ constructor(element, type=TabType.SPACES, size=null) { this.element = element; + this.oldSize = size || 4; this.set(type, size); console.log(this); } @@ -38,7 +39,6 @@ export default class Tab{ set(type, size=null){ this.type = type; this.setSize(size); - console.log(this); } /** @@ -46,6 +46,7 @@ export default class Tab{ * @param {number} size */ setSize(size){ + this.oldSize = this.size; if(this.type === TabType.TAB){ this.size = size; if(!this.size) this.size = 8; @@ -53,7 +54,6 @@ export default class Tab{ }else if(this.type === TabType.SPACES){ this.size = size; if(!this.size) this.size = 4; - console.log(this.size, size); this.element.style.tabSize = this.size*2 + 'px'; }else{ this.size = size; @@ -73,6 +73,7 @@ export default class Tab{ /** * Return spaces based on position * @param {number} position + * @return {string} */ getCompletion(position){ if(this.type === TabType.SPACES) return ' '.repeat(this.size-position%this.size); @@ -82,9 +83,21 @@ export default class Tab{ /** * Return spaces based on position * @param {number} position + * @return {number} */ getCompletionSize(position){ if(this.type === TabType.SPACES) return this.size-position%this.size; return 1; } + + /** + * Update text based on oldSize + * @param {string} text + * @return {string} + */ + updateText(text){ + const current = Math.max(text.search(/\S/), 0); + const amount = ~~(current/this.oldSize) * this.size + current%this.oldSize; + return ' '.repeat(amount) + text.slice(current) + } } diff --git a/src/routes/index.js b/src/routes/index.js index da1c297..6a26f09 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -22,6 +22,7 @@ const express = require('express'); * @type {object} */ const db = require('../db/MongoDB'); +const languages = require('../config/langages'); const config = require('../config/config'); /** * Express router. @@ -53,7 +54,9 @@ router.get('/', (req, res) => { router.post('/create_document', async (req, res, next) => { try { //const language = req.body.language - let documentId = await db.createDocument('python'); + // if (langages.includes(langage)) + const language = 'python'; + let documentId = await db.createDocument(language); if (documentId) { res.redirect(`/editor/${documentId}`); } diff --git a/src/socket/socket.js b/src/socket/socket.js index 8ae3ac0..4839098 100644 --- a/src/socket/socket.js +++ b/src/socket/socket.js @@ -8,6 +8,7 @@ */ const discordWebhook = require('webhook-discord'); const debug = require('debug'); +const languages = require('../config/langages'); const config = require('../config/config'); const prom = require('./prom'); @@ -25,6 +26,8 @@ const rooms = {}; const hook = config.DISCORD_WEBHOOK ? new discordWebhook.Webhook(config.DISCORD_WEBHOOK) : null; + + module.exports = function (wss) { // Based on https://stackoverflow.com/a/62867363 wss.on('connection', socket => { @@ -86,8 +89,11 @@ module.exports = function (wss) { case 'language': try { - broadcastRoomExceptSender(data, 'language', data.language); - const success = db.changeLanguage(data.room, data.language); + let success = false; + if (languages.includes(data.data.language)) { + broadcastRoomExceptSender(data, 'uuid', data.uuid); + success = db.changeLanguage(data.room, data.data.language); + } if (!success) socket.send(JSON.stringify({event: 'language', success: false})); } catch (err) { if (config.DEBUG) { @@ -97,8 +103,12 @@ module.exports = function (wss) { break; case 'changeTabSize': try { - broadcastRoomExceptSender(data, 'tabSize', data.tabSize); - const success = db.changeTabSize(data.room, data.tabSize); + let success = false; + data.data.size = parseInt(data.data.size); + if (Number.isInteger(data.data.size)) { + broadcastRoomExceptSender(data, 'uuid', data.uuid); + success = db.changeTabSize(data.room, data.data.size); + } if (!success) socket.send(JSON.stringify({event: 'changeTabSize', success: false})); } catch (err) { if (config.DEBUG) { diff --git a/src/views/editor.html b/src/views/editor.html index e4809f9..5850d9e 100644 --- a/src/views/editor.html +++ b/src/views/editor.html @@ -8,7 +8,7 @@ {% endblock %} {% block header %} -

CODEWE - {{ document['document_id'] }}

+

CODEWE - {{ document['document_id'] }}

@@ -20,15 +20,47 @@

CODE{{ line['content'] }}
{% endfor %} + {% endblock %} {% block scripts %} {% if production %} {% else %} {% endif %} + + {% endblock %}