diff --git a/example/tput.js b/example/tput.js index 3d0d974..d5bf925 100644 --- a/example/tput.js +++ b/example/tput.js @@ -4,3 +4,5 @@ var tput = new Tput(process.argv[2] || 'xterm'); tput.colors(); console.log(tput.info); + +tput._compile('%?%p9%t\u001b(0%e\u001b(B%;\u001b[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m'); diff --git a/lib/tput.js b/lib/tput.js index b97fbac..1c2ba53 100644 --- a/lib/tput.js +++ b/lib/tput.js @@ -303,22 +303,39 @@ Tput.prototype._compile = function(val) { // CSI Ps ; Ps r // CSI ? Pm r - var code = 'var dyn = {}, stat = {}, stack = [], out = []; out.push("'; + //var code = 'var dyn = {}, stat = {}, stack = [], out = []; out.push("'; + var ch, op, i; + var code = 'var v, dyn = {}, stat = {}, stack = [], out = []; function o(a){out.push(a);return a}' + , buff = ''; // man terminfo, around line 940 + function b() { + if (buff) { + code += 'o("'; + code += buff.replace(/([\r\n"])/g, '\\$1'); + code += '")'; + buff = ''; + } + } + while (val) { // '\e' -> ^[ if (cap = /^\\e/gi.exec(val)) { + b(); val = val.substring(cap[0].length); + code += 'o("'; code += '\x1b'; + code += '")'; continue; } // '^A' -> ^A if (cap = /^\^(.)/gi.exec(val)) { // case-insensitive? + b(); val = val.substring(cap[0].length); ch = cap[1]; + code += 'o("'; switch (ch) { case '@': code += '\x00'; @@ -420,6 +437,7 @@ Tput.prototype._compile = function(val) { code += '\x7f'; break; } + code += '")'; continue; } @@ -427,8 +445,10 @@ Tput.prototype._compile = function(val) { // '\r' -> \r // '\0' -> \200 (special case) if (cap = /^\\([nlrtbfs\^\\,:0])/g.exec(val)) { + b(); val = val.substring(cap[0].length); ch = cap[1]; + code += 'o("'; switch (ch) { case 'n': return '\n'; @@ -454,30 +474,40 @@ Tput.prototype._compile = function(val) { //return '\0'; return '\200'; } + code += '")'; continue; } // 3 octal digits -> character if (cap = /^\\(\d\d\d)/g.exec(val)) { + b(); val = val.substring(cap[0].length); ch = cap[1]; + code += 'o("'; code += String.fromCharCode(parseInt(ch, 8)); + code += '")'; continue; } // $<5> -> padding if (cap = /^\$<(\d+)>(\*|\/)/g.exec(val)) { + b(); val = val.substring(cap[0].length); ch = cap[1]; + code += 'o("'; code += Array(+ch + 1).join(' '); // "padding" characters? + code += '")'; continue; } // man terminfo, around page 1034 // %% outputs `%' if (cap = /^%%/g.exec(val)) { + b(); val = val.substring(cap[0].length); + code += 'o("'; code += '%'; + code += '")'; continue; } @@ -485,45 +515,62 @@ Tput.prototype._compile = function(val) { // as in printf, flags are [-+#] and space. Use a `:' to allow the // next character to be a `-' flag, avoiding interpreting "%-" as an // operator. - if (cap = /^%(?:(:)?([\-+# ]+)?)(?:(\d+)(\.\d+)?)?([doxXs])?/g.exec(val)) { + if (cap = /^%(?:(:)?([\-+# ]+))(?:(\d+)(\.\d+)?)?([doxXs])?/g.exec(val)) { + b(); val = val.substring(cap[0].length); + code += 'o("'; code += 'TODO'; + code += '")'; continue; } // %c print pop() like %c in printf if (cap = /^%c/g.exec(val)) { + b(); val = val.substring(cap[0].length); + code += 'o('; code += 'stack.pop()'; // TODO: FORMAT + code += ')'; continue; } // %d print pop() like %d in printf // NOT SURE ABOUT %d being print! if (cap = /^%d/g.exec(val)) { + b(); val = val.substring(cap[0].length); + code += 'o('; code += 'stack.pop()'; // TODO: FORMAT + code += ')'; continue; } // %s print pop() like %s in printf if (cap = /^%s/g.exec(val)) { + b(); val = val.substring(cap[0].length); + code += 'o('; code += 'stack.pop()'; // TODO: FORMAT + code += ')'; continue; } // %p[1-9] // push i'th parameter if (cap = /^%p([1-9])/g.exec(val)) { + b(); val = val.substring(cap[0].length); - code += 'params[i]'; + i = cap[1]; + //code += 'o('; + code += 'params[' + (i - 1) + ']'; + //code += ')'; continue; } // %P[a-z] // set dynamic variable [a-z] to pop() if (cap = /^%P([a-z])/g.exec(val)) { + b(); val = val.substring(cap[0].length); v = cap[1]; code += 'dyn.' + v + ' = stack.pop()'; @@ -533,6 +580,7 @@ Tput.prototype._compile = function(val) { // %g[a-z] // get dynamic variable [a-z] and push it if (cap = /^%g([a-z])/g.exec(val)) { + b(); val = val.substring(cap[0].length); v = cap[1]; code += '(stack.push(dyn.' + v + '), dyn.' + v + ')'; @@ -542,6 +590,7 @@ Tput.prototype._compile = function(val) { // %P[A-Z] // set static variable [a-z] to pop() if (cap = /^%P([A-Z])/g.exec(val)) { + b(); val = val.substring(cap[0].length); v = cap[1]; code += 'stat.' + v + ' = stack.pop()'; @@ -558,14 +607,16 @@ Tput.prototype._compile = function(val) { // impact portability to other implementations. if (cap = /^%g([A-Z])/g.exec(val)) { + b(); val = val.substring(cap[0].length); v = cap[1]; - code += 'stack.push(stat.' + v + ')'; + code += '(stack.push(v = stat.' + v + '), v)'; continue; } // %'c' char constant c if (cap = /^%'(\w)'/g.exec(val)) { + b(); val = val.substring(cap[0].length); ch = cap[1]; code += '"' + ch + '"'; @@ -575,6 +626,7 @@ Tput.prototype._compile = function(val) { // %{nn} // integer constant nn if (cap = /^%\{(\d+)\}/g.exec(val)) { + b(); val = val.substring(cap[0].length); ch = cap[1]; code += '(' + ch + ')'; @@ -583,8 +635,9 @@ Tput.prototype._compile = function(val) { // %l push strlen(pop) if (cap = /^%l/g.exec(val)) { + b(); val = val.substring(cap[0].length); - code += 'stack.push(stack.pop().length)'; + code += '(stack.push(v = stack.pop().length), v)'; continue; } @@ -595,17 +648,19 @@ Tput.prototype._compile = function(val) { // %= %> %< // logical operations: push(pop() op pop()) if (cap = /^%([+\-*\/m&|\^=><])/g.exec(val)) { + b(); val = val.substring(cap[0].length); op = cap[1]; if (op === '=') op = '==='; else if (op === 'm') op = '%'; - code += 'stack.push(stack.pop() ' + op + ' stack.pop())'; + code += '(stack.push(v = stack.pop() ' + op + ' stack.pop()), v)'; continue; } // %A, %O // logical AND and OR operations (for conditionals) if (cap = /^%([AO])/g.exec(val)) { + b(); val = val.substring(cap[0].length); op = cap[1]; code += op === ' A ' ? ' && ' : ' || '; @@ -615,14 +670,16 @@ Tput.prototype._compile = function(val) { // %! %~ // unary operations (logical and bit complement): push(op pop()) if (cap = /^%([!~])/g.exec(val)) { + b(); val = val.substring(cap[0].length); op = cap[1]; - code += 'stack.push(' + op + 'stack.pop())'; + code += '(stack.push(v = ' + op + 'stack.pop()), v)'; continue; } // %i add 1 to first two parameters (for ANSI terminals) if (cap = /^%i/g.exec(val)) { + b(); val = val.substring(cap[0].length); code += '(params[0]++, params[1]++)'; continue; @@ -644,26 +701,34 @@ Tput.prototype._compile = function(val) { // written on one line. The -f option splits the string into lines with // the parts indented. if (cap = /^%\?/g.exec(val)) { + b(); val = val.substring(cap[0].length); - code += '"); if ('; + //code += '"); if ('; + code += 'if ('; continue; } if (cap = /^%t/g.exec(val)) { + b(); val = val.substring(cap[0].length); - code += ') { out.push("'; + //code += ') { out.push("'; + code += ') {'; continue; } if (cap = /^%e/g.exec(val)) { + b(); val = val.substring(cap[0].length); - code += '"); } else { out.push("'; + //code += '"); } else { out.push("'; + code += '} else {'; continue; } if (cap = /^%;/g.exec(val)) { + b(); val = val.substring(cap[0].length); - code += '"); } out.push("'; + //code += '"); } out.push("'; + code += '}'; continue; } @@ -695,13 +760,19 @@ Tput.prototype._compile = function(val) { // Then the same is done for the second parameter. More complex // arithmetic is possible using the stack. - code += val[0]; + buff += val[0]; val = val.substring(1); } - code += '"); return out.join("");'; + code += 'return out.join("");'; - return new Function('params', code); + console.log(code.replace(/\x1b/g, '\\x1b')); + + try { + return new Function('params', code); + } catch (e) { + console.log(e.message); + } }; // Return alias if one exists.