12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295 |
- /**
- * program.js - basic curses-like functionality for blessed.
- * Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
- * https://github.com/chjj/blessed
- */
- /**
- * Modules
- */
- var EventEmitter = require('events').EventEmitter
- , StringDecoder = require('string_decoder').StringDecoder
- , cp = require('child_process')
- , util = require('util')
- , fs = require('fs');
- var Tput = require('./tput')
- , colors = require('./colors')
- , slice = Array.prototype.slice;
- var nextTick = global.setImmediate || process.nextTick.bind(process);
- /**
- * Program
- */
- function Program(options) {
- var self = this;
- if (!(this instanceof Program)) {
- return new Program(options);
- }
- Program.bind(this);
- EventEmitter.call(this);
- if (!options || options.__proto__ !== Object.prototype) {
- options = {
- input: arguments[0],
- output: arguments[1]
- };
- }
- this.options = options;
- this.input = options.input || process.stdin;
- this.output = options.output || process.stdout;
- options.log = options.log || options.dump;
- if (options.log) {
- this._logger = fs.createWriteStream(options.log);
- if (options.dump) this.setupDump();
- }
- this.zero = options.zero !== false;
- this.useBuffer = options.buffer;
- this.x = 0;
- this.y = 0;
- this.savedX = 0;
- this.savedY = 0;
- this.cols = this.output.columns || 1;
- this.rows = this.output.rows || 1;
- this.scrollTop = 0;
- this.scrollBottom = this.rows - 1;
- this._terminal = options.terminal
- || options.term
- || process.env.TERM
- || (process.platform === 'win32' ? 'windows-ansi' : 'xterm');
- this._terminal = this._terminal.toLowerCase();
- // OSX
- this.isOSXTerm = process.env.TERM_PROGRAM === 'Apple_Terminal';
- this.isiTerm2 = process.env.TERM_PROGRAM === 'iTerm.app'
- || !!process.env.ITERM_SESSION_ID;
- // VTE
- // NOTE: lxterminal does not provide an env variable to check for.
- // NOTE: gnome-terminal and sakura use a later version of VTE
- // which provides VTE_VERSION as well as supports SGR events.
- this.isXFCE = /xfce/i.test(process.env.COLORTERM);
- this.isTerminator = !!process.env.TERMINATOR_UUID;
- this.isLXDE = false;
- this.isVTE = !!process.env.VTE_VERSION
- || this.isXFCE
- || this.isTerminator
- || this.isLXDE;
- // xterm and rxvt - not accurate
- this.isRxvt = /rxvt/i.test(process.env.COLORTERM);
- this.isXterm = false;
- this.tmux = !!process.env.TMUX;
- this.tmuxVersion = (function() {
- if (!self.tmux) return 2;
- try {
- var version = cp.execFileSync('tmux', ['-V'], { encoding: 'utf8' });
- return +/^tmux ([\d.]+)/i.exec(version.trim().split('\n')[0])[1];
- } catch (e) {
- return 2;
- }
- })();
- this._buf = '';
- this._flush = this.flush.bind(this);
- if (options.tput !== false) {
- this.setupTput();
- }
- this.listen();
- }
- Program.global = null;
- Program.total = 0;
- Program.instances = [];
- Program.bind = function(program) {
- if (!Program.global) {
- Program.global = program;
- }
- if (!~Program.instances.indexOf(program)) {
- Program.instances.push(program);
- program.index = Program.total;
- Program.total++;
- }
- if (Program._bound) return;
- Program._bound = true;
- unshiftEvent(process, 'exit', Program._exitHandler = function() {
- Program.instances.forEach(function(program) {
- // Potentially reset window title on exit:
- // if (program._originalTitle) {
- // program.setTitle(program._originalTitle);
- // }
- // Ensure the buffer is flushed (it should
- // always be at this point, but who knows).
- program.flush();
- // Ensure _exiting is set (could technically
- // use process._exiting).
- program._exiting = true;
- });
- });
- };
- Program.prototype.__proto__ = EventEmitter.prototype;
- Program.prototype.type = 'program';
- Program.prototype.log = function() {
- return this._log('LOG', util.format.apply(util, arguments));
- };
- Program.prototype.debug = function() {
- if (!this.options.debug) return;
- return this._log('DEBUG', util.format.apply(util, arguments));
- };
- Program.prototype._log = function(pre, msg) {
- if (!this._logger) return;
- return this._logger.write(pre + ': ' + msg + '\n-\n');
- };
- Program.prototype.setupDump = function() {
- var self = this
- , write = this.output.write
- , decoder = new StringDecoder('utf8');
- function stringify(data) {
- return caret(data
- .replace(/\r/g, '\\r')
- .replace(/\n/g, '\\n')
- .replace(/\t/g, '\\t'))
- .replace(/[^ -~]/g, function(ch) {
- if (ch.charCodeAt(0) > 0xff) return ch;
- ch = ch.charCodeAt(0).toString(16);
- if (ch.length > 2) {
- if (ch.length < 4) ch = '0' + ch;
- return '\\u' + ch;
- }
- if (ch.length < 2) ch = '0' + ch;
- return '\\x' + ch;
- });
- }
- function caret(data) {
- return data.replace(/[\0\x80\x1b-\x1f\x7f\x01-\x1a]/g, function(ch) {
- switch (ch) {
- case '\0':
- case '\200':
- ch = '@';
- break;
- case '\x1b':
- ch = '[';
- break;
- case '\x1c':
- ch = '\\';
- break;
- case '\x1d':
- ch = ']';
- break;
- case '\x1e':
- ch = '^';
- break;
- case '\x1f':
- ch = '_';
- break;
- case '\x7f':
- ch = '?';
- break;
- default:
- ch = ch.charCodeAt(0);
- // From ('A' - 64) to ('Z' - 64).
- if (ch >= 1 && ch <= 26) {
- ch = String.fromCharCode(ch + 64);
- } else {
- return String.fromCharCode(ch);
- }
- break;
- }
- return '^' + ch;
- });
- }
- this.input.on('data', function(data) {
- self._log('IN', stringify(decoder.write(data)));
- });
- this.output.write = function(data) {
- self._log('OUT', stringify(data));
- return write.apply(this, arguments);
- };
- };
- Program.prototype.setupTput = function() {
- if (this._tputSetup) return;
- this._tputSetup = true;
- var self = this
- , options = this.options
- , write = this._write.bind(this);
- var tput = this.tput = new Tput({
- terminal: this.terminal,
- padding: options.padding,
- extended: options.extended,
- printf: options.printf,
- termcap: options.termcap,
- forceUnicode: options.forceUnicode
- });
- if (tput.error) {
- nextTick(function() {
- self.emit('warning', tput.error.message);
- });
- }
- if (tput.padding) {
- nextTick(function() {
- self.emit('warning', 'Terminfo padding has been enabled.');
- });
- }
- this.put = function() {
- var args = slice.call(arguments)
- , cap = args.shift();
- if (tput[cap]) {
- return this._write(tput[cap].apply(tput, args));
- }
- };
- Object.keys(tput).forEach(function(key) {
- if (self[key] == null) {
- self[key] = tput[key];
- }
- if (typeof tput[key] !== 'function') {
- self.put[key] = tput[key];
- return;
- }
- if (tput.padding) {
- self.put[key] = function() {
- return tput._print(tput[key].apply(tput, arguments), write);
- };
- } else {
- self.put[key] = function() {
- return self._write(tput[key].apply(tput, arguments));
- };
- }
- });
- };
- Program.prototype.__defineGetter__('terminal', function() {
- return this._terminal;
- });
- Program.prototype.__defineSetter__('terminal', function(terminal) {
- this.setTerminal(terminal);
- return this.terminal;
- });
- Program.prototype.setTerminal = function(terminal) {
- this._terminal = terminal.toLowerCase();
- delete this._tputSetup;
- this.setupTput();
- };
- Program.prototype.has = function(name) {
- return this.tput
- ? this.tput.has(name)
- : false;
- };
- Program.prototype.term = function(is) {
- return this.terminal.indexOf(is) === 0;
- };
- Program.prototype.listen = function() {
- var self = this;
- // Potentially reset window title on exit:
- // if (!this.isRxvt) {
- // if (!this.isVTE) this.setTitleModeFeature(3);
- // this.manipulateWindow(21, function(err, data) {
- // if (err) return;
- // self._originalTitle = data.text;
- // });
- // }
- // Listen for keys/mouse on input
- if (!this.input._blessedInput) {
- this.input._blessedInput = 1;
- this._listenInput();
- } else {
- this.input._blessedInput++;
- }
- this.on('newListener', this._newHandler = function fn(type) {
- if (type === 'keypress' || type === 'mouse') {
- self.removeListener('newListener', fn);
- if (self.input.setRawMode && !self.input.isRaw) {
- self.input.setRawMode(true);
- self.input.resume();
- }
- }
- });
- this.on('newListener', function fn(type) {
- if (type === 'mouse') {
- self.removeListener('newListener', fn);
- self.bindMouse();
- }
- });
- // Listen for resize on output
- if (!this.output._blessedOutput) {
- this.output._blessedOutput = 1;
- this._listenOutput();
- } else {
- this.output._blessedOutput++;
- }
- };
- Program.prototype._listenInput = function() {
- var keys = require('./keys')
- , self = this;
- // Input
- this.input.on('keypress', this.input._keypressHandler = function(ch, key) {
- key = key || { ch: ch };
- if (key.name === 'undefined'
- && (key.code === '[M' || key.code === '[I' || key.code === '[O')) {
- // A mouse sequence. The `keys` module doesn't understand these.
- return;
- }
- if (key.name === 'undefined') {
- // Not sure what this is, but we should probably ignore it.
- return;
- }
- if (key.name === 'enter' && key.sequence === '\n') {
- key.name = 'linefeed';
- }
- if (key.name === 'return' && key.sequence === '\r') {
- self.input.emit('keypress', ch, merge({}, key, { name: 'enter' }));
- }
- var name = (key.ctrl ? 'C-' : '')
- + (key.meta ? 'M-' : '')
- + (key.shift && key.name ? 'S-' : '')
- + (key.name || ch);
- key.full = name;
- Program.instances.forEach(function(program) {
- if (program.input !== self.input) return;
- program.emit('keypress', ch, key);
- program.emit('key ' + name, ch, key);
- });
- });
- this.input.on('data', this.input._dataHandler = function(data) {
- Program.instances.forEach(function(program) {
- if (program.input !== self.input) return;
- program.emit('data', data);
- });
- });
- keys.emitKeypressEvents(this.input);
- };
- Program.prototype._listenOutput = function() {
- var self = this;
- if (!this.output.isTTY) {
- nextTick(function() {
- self.emit('warning', 'Output is not a TTY');
- });
- }
- // Output
- function resize() {
- Program.instances.forEach(function(program) {
- if (program.output !== self.output) return;
- program.cols = program.output.columns;
- program.rows = program.output.rows;
- program.emit('resize');
- });
- }
- this.output.on('resize', this.output._resizeHandler = function() {
- Program.instances.forEach(function(program) {
- if (program.output !== self.output) return;
- if (!program.options.resizeTimeout) {
- return resize();
- }
- if (program._resizeTimer) {
- clearTimeout(program._resizeTimer);
- delete program._resizeTimer;
- }
- var time = typeof program.options.resizeTimeout === 'number'
- ? program.options.resizeTimeout
- : 300;
- program._resizeTimer = setTimeout(resize, time);
- });
- });
- };
- Program.prototype.destroy = function() {
- var index = Program.instances.indexOf(this);
- if (~index) {
- Program.instances.splice(index, 1);
- Program.total--;
- this.flush();
- this._exiting = true;
- Program.global = Program.instances[0];
- if (Program.total === 0) {
- Program.global = null;
- process.removeListener('exit', Program._exitHandler);
- delete Program._exitHandler;
- delete Program._bound;
- }
- this.input._blessedInput--;
- this.output._blessedOutput--;
- if (this.input._blessedInput === 0) {
- this.input.removeListener('keypress', this.input._keypressHandler);
- this.input.removeListener('data', this.input._dataHandler);
- delete this.input._keypressHandler;
- delete this.input._dataHandler;
- if (this.input.setRawMode) {
- if (this.input.isRaw) {
- this.input.setRawMode(false);
- }
- if (!this.input.destroyed) {
- this.input.pause();
- }
- }
- }
- if (this.output._blessedOutput === 0) {
- this.output.removeListener('resize', this.output._resizeHandler);
- delete this.output._resizeHandler;
- }
- this.removeListener('newListener', this._newHandler);
- delete this._newHandler;
- this.destroyed = true;
- this.emit('destroy');
- }
- };
- Program.prototype.key = function(key, listener) {
- if (typeof key === 'string') key = key.split(/\s*,\s*/);
- key.forEach(function(key) {
- return this.on('key ' + key, listener);
- }, this);
- };
- Program.prototype.onceKey = function(key, listener) {
- if (typeof key === 'string') key = key.split(/\s*,\s*/);
- key.forEach(function(key) {
- return this.once('key ' + key, listener);
- }, this);
- };
- Program.prototype.unkey =
- Program.prototype.removeKey = function(key, listener) {
- if (typeof key === 'string') key = key.split(/\s*,\s*/);
- key.forEach(function(key) {
- return this.removeListener('key ' + key, listener);
- }, this);
- };
- // XTerm mouse events
- // http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
- // To better understand these
- // the xterm code is very helpful:
- // Relevant files:
- // button.c, charproc.c, misc.c
- // Relevant functions in xterm/button.c:
- // BtnCode, EmitButtonCode, EditorButton, SendMousePosition
- // send a mouse event:
- // regular/utf8: ^[[M Cb Cx Cy
- // urxvt: ^[[ Cb ; Cx ; Cy M
- // sgr: ^[[ Cb ; Cx ; Cy M/m
- // vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r
- // locator: CSI P e ; P b ; P r ; P c ; P p & w
- // motion example of a left click:
- // ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
- // mouseup, mousedown, mousewheel
- // left click: ^[[M 3<^[[M#3<
- // mousewheel up: ^[[M`3>
- Program.prototype.bindMouse = function() {
- if (this._boundMouse) return;
- this._boundMouse = true;
- var decoder = new StringDecoder('utf8')
- , self = this;
- this.on('data', function(data) {
- var text = decoder.write(data);
- if (!text) return;
- self._bindMouse(text, data);
- });
- };
- Program.prototype._bindMouse = function(s, buf) {
- var self = this
- , key
- , parts
- , b
- , x
- , y
- , mod
- , params
- , down
- , page
- , button;
- key = {
- name: undefined,
- ctrl: false,
- meta: false,
- shift: false
- };
- if (Buffer.isBuffer(s)) {
- if (s[0] > 127 && s[1] === undefined) {
- s[0] -= 128;
- s = '\x1b' + s.toString('utf-8');
- } else {
- s = s.toString('utf-8');
- }
- }
- // if (this.8bit) {
- // s = s.replace(/\233/g, '\x1b[');
- // buf = new Buffer(s, 'utf8');
- // }
- // XTerm / X10 for buggy VTE
- // VTE can only send unsigned chars and no unicode for coords. This limits
- // them to 0xff. However, normally the x10 protocol does not allow a byte
- // under 0x20, but since VTE can have the bytes overflow, we can consider
- // bytes below 0x20 to be up to 0xff + 0x20. This gives a limit of 287. Since
- // characters ranging from 223 to 248 confuse javascript's utf parser, we
- // need to parse the raw binary. We can detect whether the terminal is using
- // a bugged VTE version by examining the coordinates and seeing whether they
- // are a value they would never otherwise be with a properly implemented x10
- // protocol. This method of detecting VTE is only 99% reliable because we
- // can't check if the coords are 0x00 (255) since that is a valid x10 coord
- // technically.
- var bx = s.charCodeAt(4);
- var by = s.charCodeAt(5);
- if (buf[0] === 0x1b && buf[1] === 0x5b && buf[2] === 0x4d
- && (this.isVTE
- || bx >= 65533 || by >= 65533
- || (bx > 0x00 && bx < 0x20)
- || (by > 0x00 && by < 0x20)
- || (buf[4] > 223 && buf[4] < 248 && buf.length === 6)
- || (buf[5] > 223 && buf[5] < 248 && buf.length === 6))) {
- b = buf[3];
- x = buf[4];
- y = buf[5];
- // unsigned char overflow.
- if (x < 0x20) x += 0xff;
- if (y < 0x20) y += 0xff;
- // Convert the coordinates into a
- // properly formatted x10 utf8 sequence.
- s = '\x1b[M'
- + String.fromCharCode(b)
- + String.fromCharCode(x)
- + String.fromCharCode(y);
- }
- // XTerm / X10
- if (parts = /^\x1b\[M([\x00\u0020-\uffff]{3})/.exec(s)) {
- b = parts[1].charCodeAt(0);
- x = parts[1].charCodeAt(1);
- y = parts[1].charCodeAt(2);
- key.name = 'mouse';
- key.type = 'X10';
- key.raw = [b, x, y, parts[0]];
- key.buf = buf;
- key.x = x - 32;
- key.y = y - 32;
- if (this.zero) key.x--, key.y--;
- if (x === 0) key.x = 255;
- if (y === 0) key.y = 255;
- mod = b >> 2;
- key.shift = !!(mod & 1);
- key.meta = !!((mod >> 1) & 1);
- key.ctrl = !!((mod >> 2) & 1);
- b -= 32;
- if ((b >> 6) & 1) {
- key.action = b & 1 ? 'wheeldown' : 'wheelup';
- key.button = 'middle';
- } else if (b === 3) {
- // NOTE: x10 and urxvt have no way
- // of telling which button mouseup used.
- key.action = 'mouseup';
- key.button = this._lastButton || 'unknown';
- delete this._lastButton;
- } else {
- key.action = 'mousedown';
- button = b & 3;
- key.button =
- button === 0 ? 'left'
- : button === 1 ? 'middle'
- : button === 2 ? 'right'
- : 'unknown';
- this._lastButton = key.button;
- }
- // Probably a movement.
- // The *newer* VTE gets mouse movements comepletely wrong.
- // This presents a problem: older versions of VTE that get it right might
- // be confused by the second conditional in the if statement.
- // NOTE: Possibly just switch back to the if statement below.
- // none, shift, ctrl, alt
- // gnome: 32, 36, 48, 40
- // xterm: 35, _, 51, _
- // urxvt: 35, _, _, _
- // if (key.action === 'mousedown' && key.button === 'unknown') {
- if (b === 35 || b === 39 || b === 51 || b === 43
- || (this.isVTE && (b === 32 || b === 36 || b === 48 || b === 40))) {
- delete key.button;
- key.action = 'mousemove';
- }
- self.emit('mouse', key);
- return;
- }
- // URxvt
- if (parts = /^\x1b\[(\d+;\d+;\d+)M/.exec(s)) {
- params = parts[1].split(';');
- b = +params[0];
- x = +params[1];
- y = +params[2];
- key.name = 'mouse';
- key.type = 'urxvt';
- key.raw = [b, x, y, parts[0]];
- key.buf = buf;
- key.x = x;
- key.y = y;
- if (this.zero) key.x--, key.y--;
- mod = b >> 2;
- key.shift = !!(mod & 1);
- key.meta = !!((mod >> 1) & 1);
- key.ctrl = !!((mod >> 2) & 1);
- // XXX Bug in urxvt after wheelup/down on mousemove
- // NOTE: This may be different than 128/129 depending
- // on mod keys.
- if (b === 128 || b === 129) {
- b = 67;
- }
- b -= 32;
- if ((b >> 6) & 1) {
- key.action = b & 1 ? 'wheeldown' : 'wheelup';
- key.button = 'middle';
- } else if (b === 3) {
- // NOTE: x10 and urxvt have no way
- // of telling which button mouseup used.
- key.action = 'mouseup';
- key.button = this._lastButton || 'unknown';
- delete this._lastButton;
- } else {
- key.action = 'mousedown';
- button = b & 3;
- key.button =
- button === 0 ? 'left'
- : button === 1 ? 'middle'
- : button === 2 ? 'right'
- : 'unknown';
- // NOTE: 0/32 = mousemove, 32/64 = mousemove with left down
- // if ((b >> 1) === 32)
- this._lastButton = key.button;
- }
- // Probably a movement.
- // The *newer* VTE gets mouse movements comepletely wrong.
- // This presents a problem: older versions of VTE that get it right might
- // be confused by the second conditional in the if statement.
- // NOTE: Possibly just switch back to the if statement below.
- // none, shift, ctrl, alt
- // urxvt: 35, _, _, _
- // gnome: 32, 36, 48, 40
- // if (key.action === 'mousedown' && key.button === 'unknown') {
- if (b === 35 || b === 39 || b === 51 || b === 43
- || (this.isVTE && (b === 32 || b === 36 || b === 48 || b === 40))) {
- delete key.button;
- key.action = 'mousemove';
- }
- self.emit('mouse', key);
- return;
- }
- // SGR
- if (parts = /^\x1b\[<(\d+;\d+;\d+)([mM])/.exec(s)) {
- down = parts[2] === 'M';
- params = parts[1].split(';');
- b = +params[0];
- x = +params[1];
- y = +params[2];
- key.name = 'mouse';
- key.type = 'sgr';
- key.raw = [b, x, y, parts[0]];
- key.buf = buf;
- key.x = x;
- key.y = y;
- if (this.zero) key.x--, key.y--;
- mod = b >> 2;
- key.shift = !!(mod & 1);
- key.meta = !!((mod >> 1) & 1);
- key.ctrl = !!((mod >> 2) & 1);
- if ((b >> 6) & 1) {
- key.action = b & 1 ? 'wheeldown' : 'wheelup';
- key.button = 'middle';
- } else {
- key.action = down
- ? 'mousedown'
- : 'mouseup';
- button = b & 3;
- key.button =
- button === 0 ? 'left'
- : button === 1 ? 'middle'
- : button === 2 ? 'right'
- : 'unknown';
- }
- // Probably a movement.
- // The *newer* VTE gets mouse movements comepletely wrong.
- // This presents a problem: older versions of VTE that get it right might
- // be confused by the second conditional in the if statement.
- // NOTE: Possibly just switch back to the if statement below.
- // none, shift, ctrl, alt
- // xterm: 35, _, 51, _
- // gnome: 32, 36, 48, 40
- // if (key.action === 'mousedown' && key.button === 'unknown') {
- if (b === 35 || b === 39 || b === 51 || b === 43
- || (this.isVTE && (b === 32 || b === 36 || b === 48 || b === 40))) {
- delete key.button;
- key.action = 'mousemove';
- }
- self.emit('mouse', key);
- return;
- }
- // DEC
- // The xterm mouse documentation says there is a
- // `<` prefix, the DECRQLP says there is no prefix.
- if (parts = /^\x1b\[<(\d+;\d+;\d+;\d+)&w/.exec(s)) {
- params = parts[1].split(';');
- b = +params[0];
- x = +params[1];
- y = +params[2];
- page = +params[3];
- key.name = 'mouse';
- key.type = 'dec';
- key.raw = [b, x, y, parts[0]];
- key.buf = buf;
- key.x = x;
- key.y = y;
- key.page = page;
- if (this.zero) key.x--, key.y--;
- key.action = b === 3
- ? 'mouseup'
- : 'mousedown';
- key.button =
- b === 2 ? 'left'
- : b === 4 ? 'middle'
- : b === 6 ? 'right'
- : 'unknown';
- self.emit('mouse', key);
- return;
- }
- // vt300
- if (parts = /^\x1b\[24([0135])~\[(\d+),(\d+)\]\r/.exec(s)) {
- b = +parts[1];
- x = +parts[2];
- y = +parts[3];
- key.name = 'mouse';
- key.type = 'vt300';
- key.raw = [b, x, y, parts[0]];
- key.buf = buf;
- key.x = x;
- key.y = y;
- if (this.zero) key.x--, key.y--;
- key.action = 'mousedown';
- key.button =
- b === 1 ? 'left'
- : b === 2 ? 'middle'
- : b === 5 ? 'right'
- : 'unknown';
- self.emit('mouse', key);
- return;
- }
- if (parts = /^\x1b\[(O|I)/.exec(s)) {
- key.action = parts[1] === 'I'
- ? 'focus'
- : 'blur';
- self.emit('mouse', key);
- self.emit(key.action);
- return;
- }
- };
- // gpm support for linux vc
- Program.prototype.enableGpm = function() {
- var self = this;
- var gpmclient = require('./gpmclient');
- if (this.gpm) return;
- this.gpm = gpmclient();
- this.gpm.on('btndown', function(btn, modifier, x, y) {
- x--, y--;
- var key = {
- name: 'mouse',
- type: 'GPM',
- action: 'mousedown',
- button: self.gpm.ButtonName(btn),
- raw: [btn, modifier, x, y],
- x: x,
- y: y,
- shift: self.gpm.hasShiftKey(modifier),
- meta: self.gpm.hasMetaKey(modifier),
- ctrl: self.gpm.hasCtrlKey(modifier)
- };
- self.emit('mouse', key);
- });
- this.gpm.on('btnup', function(btn, modifier, x, y) {
- x--, y--;
- var key = {
- name: 'mouse',
- type: 'GPM',
- action: 'mouseup',
- button: self.gpm.ButtonName(btn),
- raw: [btn, modifier, x, y],
- x: x,
- y: y,
- shift: self.gpm.hasShiftKey(modifier),
- meta: self.gpm.hasMetaKey(modifier),
- ctrl: self.gpm.hasCtrlKey(modifier)
- };
- self.emit('mouse', key);
- });
- this.gpm.on('move', function(btn, modifier, x, y) {
- x--, y--;
- var key = {
- name: 'mouse',
- type: 'GPM',
- action: 'mousemove',
- button: self.gpm.ButtonName(btn),
- raw: [btn, modifier, x, y],
- x: x,
- y: y,
- shift: self.gpm.hasShiftKey(modifier),
- meta: self.gpm.hasMetaKey(modifier),
- ctrl: self.gpm.hasCtrlKey(modifier)
- };
- self.emit('mouse', key);
- });
- this.gpm.on('drag', function(btn, modifier, x, y) {
- x--, y--;
- var key = {
- name: 'mouse',
- type: 'GPM',
- action: 'mousemove',
- button: self.gpm.ButtonName(btn),
- raw: [btn, modifier, x, y],
- x: x,
- y: y,
- shift: self.gpm.hasShiftKey(modifier),
- meta: self.gpm.hasMetaKey(modifier),
- ctrl: self.gpm.hasCtrlKey(modifier)
- };
- self.emit('mouse', key);
- });
- this.gpm.on('mousewheel', function(btn, modifier, x, y, dx, dy) {
- var key = {
- name: 'mouse',
- type: 'GPM',
- action: dy > 0 ? 'wheelup' : 'wheeldown',
- button: self.gpm.ButtonName(btn),
- raw: [btn, modifier, x, y, dx, dy],
- x: x,
- y: y,
- shift: self.gpm.hasShiftKey(modifier),
- meta: self.gpm.hasMetaKey(modifier),
- ctrl: self.gpm.hasCtrlKey(modifier)
- };
- self.emit('mouse', key);
- });
- };
- Program.prototype.disableGpm = function() {
- if (this.gpm) {
- this.gpm.stop();
- delete this.gpm;
- }
- };
- // All possible responses from the terminal
- Program.prototype.bindResponse = function() {
- if (this._boundResponse) return;
- this._boundResponse = true;
- var decoder = new StringDecoder('utf8')
- , self = this;
- this.on('data', function(data) {
- data = decoder.write(data);
- if (!data) return;
- self._bindResponse(data);
- });
- };
- Program.prototype._bindResponse = function(s) {
- var out = {}
- , parts;
- if (Buffer.isBuffer(s)) {
- if (s[0] > 127 && s[1] === undefined) {
- s[0] -= 128;
- s = '\x1b' + s.toString('utf-8');
- } else {
- s = s.toString('utf-8');
- }
- }
- // CSI P s c
- // Send Device Attributes (Primary DA).
- // CSI > P s c
- // Send Device Attributes (Secondary DA).
- if (parts = /^\x1b\[(\?|>)(\d*(?:;\d*)*)c/.exec(s)) {
- parts = parts[2].split(';').map(function(ch) {
- return +ch || 0;
- });
- out.event = 'device-attributes';
- out.code = 'DA';
- if (parts[1] === '?') {
- out.type = 'primary-attribute';
- // VT100-style params:
- if (parts[0] === 1 && parts[2] === 2) {
- out.term = 'vt100';
- out.advancedVideo = true;
- } else if (parts[0] === 1 && parts[2] === 0) {
- out.term = 'vt101';
- } else if (parts[0] === 6) {
- out.term = 'vt102';
- } else if (parts[0] === 60
- && parts[1] === 1 && parts[2] === 2
- && parts[3] === 6 && parts[4] === 8
- && parts[5] === 9 && parts[6] === 15) {
- out.term = 'vt220';
- } else {
- // VT200-style params:
- parts.forEach(function(attr) {
- switch (attr) {
- case 1:
- out.cols132 = true;
- break;
- case 2:
- out.printer = true;
- break;
- case 6:
- out.selectiveErase = true;
- break;
- case 8:
- out.userDefinedKeys = true;
- break;
- case 9:
- out.nationalReplacementCharsets = true;
- break;
- case 15:
- out.technicalCharacters = true;
- break;
- case 18:
- out.userWindows = true;
- break;
- case 21:
- out.horizontalScrolling = true;
- break;
- case 22:
- out.ansiColor = true;
- break;
- case 29:
- out.ansiTextLocator = true;
- break;
- }
- });
- }
- } else {
- out.type = 'secondary-attribute';
- switch (parts[0]) {
- case 0:
- out.term = 'vt100';
- break;
- case 1:
- out.term = 'vt220';
- break;
- case 2:
- out.term = 'vt240';
- break;
- case 18:
- out.term = 'vt330';
- break;
- case 19:
- out.term = 'vt340';
- break;
- case 24:
- out.term = 'vt320';
- break;
- case 41:
- out.term = 'vt420';
- break;
- case 61:
- out.term = 'vt510';
- break;
- case 64:
- out.term = 'vt520';
- break;
- case 65:
- out.term = 'vt525';
- break;
- }
- out.firmwareVersion = parts[1];
- out.romCartridgeRegistrationNumber = parts[2];
- }
- // LEGACY
- out.deviceAttributes = out;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- // CSI Ps n Device Status Report (DSR).
- // Ps = 5 -> Status Report. Result (``OK'') is
- // CSI 0 n
- // CSI ? Ps n
- // Device Status Report (DSR, DEC-specific).
- // Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready).
- // or CSI ? 1 1 n (not ready).
- // Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked)
- // or CSI ? 2 1 n (locked).
- // Ps = 2 6 -> Report Keyboard status as
- // CSI ? 2 7 ; 1 ; 0 ; 0 n (North American).
- // The last two parameters apply to VT400 & up, and denote key-
- // board ready and LK01 respectively.
- // Ps = 5 3 -> Report Locator status as
- // CSI ? 5 3 n Locator available, if compiled-in, or
- // CSI ? 5 0 n No Locator, if not.
- if (parts = /^\x1b\[(\?)?(\d+)(?:;(\d+);(\d+);(\d+))?n/.exec(s)) {
- out.event = 'device-status';
- out.code = 'DSR';
- if (!parts[1] && parts[2] === '0' && !parts[3]) {
- out.type = 'device-status';
- out.status = 'OK';
- // LEGACY
- out.deviceStatus = out.status;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- if (parts[1] && (parts[2] === '10' || parts[2] === '11') && !parts[3]) {
- out.type = 'printer-status';
- out.status = parts[2] === '10'
- ? 'ready'
- : 'not ready';
- // LEGACY
- out.printerStatus = out.status;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- if (parts[1] && (parts[2] === '20' || parts[2] === '21') && !parts[3]) {
- out.type = 'udk-status';
- out.status = parts[2] === '20'
- ? 'unlocked'
- : 'locked';
- // LEGACY
- out.UDKStatus = out.status;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- if (parts[1]
- && parts[2] === '27'
- && parts[3] === '1'
- && parts[4] === '0'
- && parts[5] === '0') {
- out.type = 'keyboard-status';
- out.status = 'OK';
- // LEGACY
- out.keyboardStatus = out.status;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- if (parts[1] && (parts[2] === '53' || parts[2] === '50') && !parts[3]) {
- out.type = 'locator-status';
- out.status = parts[2] === '53'
- ? 'available'
- : 'unavailable';
- // LEGACY
- out.locator = out.status;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- out.type = 'error';
- out.text = 'Unhandled: ' + JSON.stringify(parts);
- // LEGACY
- out.error = out.text;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- // CSI Ps n Device Status Report (DSR).
- // Ps = 6 -> Report Cursor Position (CPR) [row;column].
- // Result is
- // CSI r ; c R
- // CSI ? Ps n
- // Device Status Report (DSR, DEC-specific).
- // Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI
- // ? r ; c R (assumes page is zero).
- if (parts = /^\x1b\[(\?)?(\d+);(\d+)R/.exec(s)) {
- out.event = 'device-status';
- out.code = 'DSR';
- out.type = 'cursor-status';
- out.status = {
- x: +parts[3],
- y: +parts[2],
- page: !parts[1] ? undefined : 0
- };
- out.x = out.status.x;
- out.y = out.status.y;
- out.page = out.status.page;
- // LEGACY
- out.cursor = out.status;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- // CSI Ps ; Ps ; Ps t
- // Window manipulation (from dtterm, as well as extensions).
- // These controls may be disabled using the allowWindowOps
- // resource. Valid values for the first (and any additional
- // parameters) are:
- // Ps = 1 1 -> Report xterm window state. If the xterm window
- // is open (non-iconified), it returns CSI 1 t . If the xterm
- // window is iconified, it returns CSI 2 t .
- // Ps = 1 3 -> Report xterm window position. Result is CSI 3
- // ; x ; y t
- // Ps = 1 4 -> Report xterm window in pixels. Result is CSI
- // 4 ; height ; width t
- // Ps = 1 8 -> Report the size of the text area in characters.
- // Result is CSI 8 ; height ; width t
- // Ps = 1 9 -> Report the size of the screen in characters.
- // Result is CSI 9 ; height ; width t
- if (parts = /^\x1b\[(\d+)(?:;(\d+);(\d+))?t/.exec(s)) {
- out.event = 'window-manipulation';
- out.code = '';
- if ((parts[1] === '1' || parts[1] === '2') && !parts[2]) {
- out.type = 'window-state';
- out.state = parts[1] === '1'
- ? 'non-iconified'
- : 'iconified';
- // LEGACY
- out.windowState = out.state;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- if (parts[1] === '3' && parts[2]) {
- out.type = 'window-position';
- out.position = {
- x: +parts[2],
- y: +parts[3]
- };
- out.x = out.position.x;
- out.y = out.position.y;
- // LEGACY
- out.windowPosition = out.position;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- if (parts[1] === '4' && parts[2]) {
- out.type = 'window-size-pixels';
- out.size = {
- height: +parts[2],
- width: +parts[3]
- };
- out.height = out.size.height;
- out.width = out.size.width;
- // LEGACY
- out.windowSizePixels = out.size;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- if (parts[1] === '8' && parts[2]) {
- out.type = 'textarea-size';
- out.size = {
- height: +parts[2],
- width: +parts[3]
- };
- out.height = out.size.height;
- out.width = out.size.width;
- // LEGACY
- out.textAreaSizeCharacters = out.size;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- if (parts[1] === '9' && parts[2]) {
- out.type = 'screen-size';
- out.size = {
- height: +parts[2],
- width: +parts[3]
- };
- out.height = out.size.height;
- out.width = out.size.width;
- // LEGACY
- out.screenSizeCharacters = out.size;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- out.type = 'error';
- out.text = 'Unhandled: ' + JSON.stringify(parts);
- // LEGACY
- out.error = out.text;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- // rxvt-unicode does not support window manipulation
- // Result Normal: OSC l/L 0xEF 0xBF 0xBD
- // Result ASCII: OSC l/L 0x1c (file separator)
- // Result UTF8->ASCII: OSC l/L 0xFD
- // Test with:
- // echo -ne '\ePtmux;\e\e[>3t\e\\'
- // sleep 2 && echo -ne '\ePtmux;\e\e[21t\e\\' & cat -v
- // -
- // echo -ne '\e[>3t'
- // sleep 2 && echo -ne '\e[21t' & cat -v
- if (parts = /^\x1b\](l|L)([^\x07\x1b]*)$/.exec(s)) {
- parts[2] = 'rxvt';
- s = '\x1b]' + parts[1] + parts[2] + '\x1b\\';
- }
- // CSI Ps ; Ps ; Ps t
- // Window manipulation (from dtterm, as well as extensions).
- // These controls may be disabled using the allowWindowOps
- // resource. Valid values for the first (and any additional
- // parameters) are:
- // Ps = 2 0 -> Report xterm window's icon label. Result is
- // OSC L label ST
- // Ps = 2 1 -> Report xterm window's title. Result is OSC l
- // label ST
- if (parts = /^\x1b\](l|L)([^\x07\x1b]*)(?:\x07|\x1b\\)/.exec(s)) {
- out.event = 'window-manipulation';
- out.code = '';
- if (parts[1] === 'L') {
- out.type = 'window-icon-label';
- out.text = parts[2];
- // LEGACY
- out.windowIconLabel = out.text;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- if (parts[1] === 'l') {
- out.type = 'window-title';
- out.text = parts[2];
- // LEGACY
- out.windowTitle = out.text;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- out.type = 'error';
- out.text = 'Unhandled: ' + JSON.stringify(parts);
- // LEGACY
- out.error = out.text;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- // CSI Ps ' |
- // Request Locator Position (DECRQLP).
- // -> CSI Pe ; Pb ; Pr ; Pc ; Pp & w
- // Parameters are [event;button;row;column;page].
- // Valid values for the event:
- // Pe = 0 -> locator unavailable - no other parameters sent.
- // Pe = 1 -> request - xterm received a DECRQLP.
- // Pe = 2 -> left button down.
- // Pe = 3 -> left button up.
- // Pe = 4 -> middle button down.
- // Pe = 5 -> middle button up.
- // Pe = 6 -> right button down.
- // Pe = 7 -> right button up.
- // Pe = 8 -> M4 button down.
- // Pe = 9 -> M4 button up.
- // Pe = 1 0 -> locator outside filter rectangle.
- // ``button'' parameter is a bitmask indicating which buttons are
- // pressed:
- // Pb = 0 <- no buttons down.
- // Pb & 1 <- right button down.
- // Pb & 2 <- middle button down.
- // Pb & 4 <- left button down.
- // Pb & 8 <- M4 button down.
- // ``row'' and ``column'' parameters are the coordinates of the
- // locator position in the xterm window, encoded as ASCII deci-
- // mal.
- // The ``page'' parameter is not used by xterm, and will be omit-
- // ted.
- // NOTE:
- // This is already implemented in the _bindMouse
- // method, but it might make more sense here.
- // The xterm mouse documentation says there is a
- // `<` prefix, the DECRQLP says there is no prefix.
- if (parts = /^\x1b\[(\d+(?:;\d+){4})&w/.exec(s)) {
- parts = parts[1].split(';').map(function(ch) {
- return +ch;
- });
- out.event = 'locator-position';
- out.code = 'DECRQLP';
- switch (parts[0]) {
- case 0:
- out.status = 'locator-unavailable';
- break;
- case 1:
- out.status = 'request';
- break;
- case 2:
- out.status = 'left-button-down';
- break;
- case 3:
- out.status = 'left-button-up';
- break;
- case 4:
- out.status = 'middle-button-down';
- break;
- case 5:
- out.status = 'middle-button-up';
- break;
- case 6:
- out.status = 'right-button-down';
- break;
- case 7:
- out.status = 'right-button-up';
- break;
- case 8:
- out.status = 'm4-button-down';
- break;
- case 9:
- out.status = 'm4-button-up';
- break;
- case 10:
- out.status = 'locator-outside';
- break;
- }
- out.mask = parts[1];
- out.row = parts[2];
- out.col = parts[3];
- out.page = parts[4];
- // LEGACY
- out.locatorPosition = out;
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- return;
- }
- // OSC Ps ; Pt BEL
- // OSC Ps ; Pt ST
- // Set Text Parameters
- if (parts = /^\x1b\](\d+);([^\x07\x1b]+)(?:\x07|\x1b\\)/.exec(s)) {
- out.event = 'text-params';
- out.code = 'Set Text Parameters';
- out.ps = +s[1];
- out.pt = s[2];
- this.emit('response', out);
- this.emit('response ' + out.event, out);
- }
- };
- Program.prototype.response = function(name, text, callback, noBypass) {
- var self = this;
- if (arguments.length === 2) {
- callback = text;
- text = name;
- name = null;
- }
- if (!callback) {
- callback = function() {};
- }
- this.bindResponse();
- name = name
- ? 'response ' + name
- : 'response';
- var onresponse;
- this.once(name, onresponse = function(event) {
- if (timeout) clearTimeout(timeout);
- if (event.type === 'error') {
- return callback(new Error(event.event + ': ' + event.text));
- }
- return callback(null, event);
- });
- var timeout = setTimeout(function() {
- self.removeListener(name, onresponse);
- return callback(new Error('Timeout.'));
- }, 2000);
- return noBypass
- ? this._write(text)
- : this._twrite(text);
- };
- Program.prototype._owrite =
- Program.prototype.write = function(text) {
- if (!this.output.writable) return;
- return this.output.write(text);
- };
- Program.prototype._buffer = function(text) {
- if (this._exiting) {
- this.flush();
- this._owrite(text);
- return;
- }
- if (this._buf) {
- this._buf += text;
- return;
- }
- this._buf = text;
- nextTick(this._flush);
- return true;
- };
- Program.prototype.flush = function() {
- if (!this._buf) return;
- this._owrite(this._buf);
- this._buf = '';
- };
- Program.prototype._write = function(text) {
- if (this.ret) return text;
- if (this.useBuffer) {
- return this._buffer(text);
- }
- return this._owrite(text);
- };
- // Example: `DCS tmux; ESC Pt ST`
- // Real: `DCS tmux; ESC Pt ESC \`
- Program.prototype._twrite = function(data) {
- var self = this
- , iterations = 0
- , timer;
- if (this.tmux) {
- // Replace all STs with BELs so they can be nested within the DCS code.
- data = data.replace(/\x1b\\/g, '\x07');
- // Wrap in tmux forward DCS:
- data = '\x1bPtmux;\x1b' + data + '\x1b\\';
- // If we've never even flushed yet, it means we're still in
- // the normal buffer. Wait for alt screen buffer.
- if (this.output.bytesWritten === 0) {
- timer = setInterval(function() {
- if (self.output.bytesWritten > 0 || ++iterations === 50) {
- clearInterval(timer);
- self.flush();
- self._owrite(data);
- }
- }, 100);
- return true;
- }
- // NOTE: Flushing the buffer is required in some cases.
- // The DCS code must be at the start of the output.
- this.flush();
- // Write out raw now that the buffer is flushed.
- return this._owrite(data);
- }
- return this._write(data);
- };
- Program.prototype.echo =
- Program.prototype.print = function(text, attr) {
- return attr
- ? this._write(this.text(text, attr))
- : this._write(text);
- };
- Program.prototype._ncoords = function() {
- if (this.x < 0) this.x = 0;
- else if (this.x >= this.cols) this.x = this.cols - 1;
- if (this.y < 0) this.y = 0;
- else if (this.y >= this.rows) this.y = this.rows - 1;
- };
- Program.prototype.setx = function(x) {
- return this.cursorCharAbsolute(x);
- // return this.charPosAbsolute(x);
- };
- Program.prototype.sety = function(y) {
- return this.linePosAbsolute(y);
- };
- Program.prototype.move = function(x, y) {
- return this.cursorPos(y, x);
- };
- // TODO: Fix cud and cuu calls.
- Program.prototype.omove = function(x, y) {
- if (!this.zero) {
- x = (x || 1) - 1;
- y = (y || 1) - 1;
- } else {
- x = x || 0;
- y = y || 0;
- }
- if (y === this.y && x === this.x) {
- return;
- }
- if (y === this.y) {
- if (x > this.x) {
- this.cuf(x - this.x);
- } else if (x < this.x) {
- this.cub(this.x - x);
- }
- } else if (x === this.x) {
- if (y > this.y) {
- this.cud(y - this.y);
- } else if (y < this.y) {
- this.cuu(this.y - y);
- }
- } else {
- if (!this.zero) x++, y++;
- this.cup(y, x);
- }
- };
- Program.prototype.rsetx = function(x) {
- // return this.HPositionRelative(x);
- if (!x) return;
- return x > 0
- ? this.forward(x)
- : this.back(-x);
- };
- Program.prototype.rsety = function(y) {
- // return this.VPositionRelative(y);
- if (!y) return;
- return y > 0
- ? this.up(y)
- : this.down(-y);
- };
- Program.prototype.rmove = function(x, y) {
- this.rsetx(x);
- this.rsety(y);
- };
- Program.prototype.simpleInsert = function(ch, i, attr) {
- return this._write(this.repeat(ch, i), attr);
- };
- Program.prototype.repeat = function(ch, i) {
- if (!i || i < 0) i = 0;
- return Array(i + 1).join(ch);
- };
- Program.prototype.__defineGetter__('title', function() {
- return this._title;
- });
- Program.prototype.__defineSetter__('title', function(title) {
- this.setTitle(title);
- return this._title;
- });
- // Specific to iTerm2, but I think it's really cool.
- // Example:
- // if (!screen.copyToClipboard(text)) {
- // execClipboardProgram(text);
- // }
- Program.prototype.copyToClipboard = function(text) {
- if (this.isiTerm2) {
- this._twrite('\x1b]50;CopyToCliboard=' + text + '\x07');
- return true;
- }
- return false;
- };
- // Only XTerm and iTerm2. If you know of any others, post them.
- Program.prototype.cursorShape = function(shape, blink) {
- if (this.isiTerm2) {
- switch (shape) {
- case 'block':
- if (!blink) {
- this._twrite('\x1b]50;CursorShape=0;BlinkingCursorEnabled=0\x07');
- } else {
- this._twrite('\x1b]50;CursorShape=0;BlinkingCursorEnabled=1\x07');
- }
- break;
- case 'underline':
- if (!blink) {
- // this._twrite('\x1b]50;CursorShape=n;BlinkingCursorEnabled=0\x07');
- } else {
- // this._twrite('\x1b]50;CursorShape=n;BlinkingCursorEnabled=1\x07');
- }
- break;
- case 'line':
- if (!blink) {
- this._twrite('\x1b]50;CursorShape=1;BlinkingCursorEnabled=0\x07');
- } else {
- this._twrite('\x1b]50;CursorShape=1;BlinkingCursorEnabled=1\x07');
- }
- break;
- }
- return true;
- } else if (this.term('xterm') || this.term('screen')) {
- switch (shape) {
- case 'block':
- if (!blink) {
- this._twrite('\x1b[0 q');
- } else {
- this._twrite('\x1b[1 q');
- }
- break;
- case 'underline':
- if (!blink) {
- this._twrite('\x1b[2 q');
- } else {
- this._twrite('\x1b[3 q');
- }
- break;
- case 'line':
- if (!blink) {
- this._twrite('\x1b[4 q');
- } else {
- this._twrite('\x1b[5 q');
- }
- break;
- }
- return true;
- }
- return false;
- };
- Program.prototype.cursorColor = function(color) {
- if (this.term('xterm') || this.term('rxvt') || this.term('screen')) {
- this._twrite('\x1b]12;' + color + '\x07');
- return true;
- }
- return false;
- };
- Program.prototype.cursorReset =
- Program.prototype.resetCursor = function() {
- if (this.term('xterm') || this.term('rxvt') || this.term('screen')) {
- // XXX
- // return this.resetColors();
- this._twrite('\x1b[0 q');
- this._twrite('\x1b]112\x07');
- // urxvt doesnt support OSC 112
- this._twrite('\x1b]12;white\x07');
- return true;
- }
- return false;
- };
- Program.prototype.getTextParams = function(param, callback) {
- return this.response('text-params', '\x1b]' + param + ';?\x07', function(err, data) {
- if (err) return callback(err);
- return callback(null, data.pt);
- });
- };
- Program.prototype.getCursorColor = function(callback) {
- return this.getTextParams(12, callback);
- };
- /**
- * Normal
- */
- //Program.prototype.pad =
- Program.prototype.nul = function() {
- //if (this.has('pad')) return this.put.pad();
- return this._write('\200');
- };
- Program.prototype.bel =
- Program.prototype.bell = function() {
- if (this.has('bel')) return this.put.bel();
- return this._write('\x07');
- };
- Program.prototype.vtab = function() {
- this.y++;
- this._ncoords();
- return this._write('\x0b');
- };
- Program.prototype.ff =
- Program.prototype.form = function() {
- if (this.has('ff')) return this.put.ff();
- return this._write('\x0c');
- };
- Program.prototype.kbs =
- Program.prototype.backspace = function() {
- this.x--;
- this._ncoords();
- if (this.has('kbs')) return this.put.kbs();
- return this._write('\x08');
- };
- Program.prototype.ht =
- Program.prototype.tab = function() {
- this.x += 8;
- this._ncoords();
- if (this.has('ht')) return this.put.ht();
- return this._write('\t');
- };
- Program.prototype.shiftOut = function() {
- // if (this.has('S2')) return this.put.S2();
- return this._write('\x0e');
- };
- Program.prototype.shiftIn = function() {
- // if (this.has('S3')) return this.put.S3();
- return this._write('\x0f');
- };
- Program.prototype.cr =
- Program.prototype.return = function() {
- this.x = 0;
- if (this.has('cr')) return this.put.cr();
- return this._write('\r');
- };
- Program.prototype.nel =
- Program.prototype.newline =
- Program.prototype.feed = function() {
- if (this.tput && this.tput.bools.eat_newline_glitch && this.x >= this.cols) {
- return;
- }
- this.x = 0;
- this.y++;
- this._ncoords();
- if (this.has('nel')) return this.put.nel();
- return this._write('\n');
- };
- /**
- * Esc
- */
- // ESC D Index (IND is 0x84).
- Program.prototype.ind =
- Program.prototype.index = function() {
- this.y++;
- this._ncoords();
- if (this.tput) return this.put.ind();
- return this._write('\x1bD');
- };
- // ESC M Reverse Index (RI is 0x8d).
- Program.prototype.ri =
- Program.prototype.reverse =
- Program.prototype.reverseIndex = function() {
- this.y--;
- this._ncoords();
- if (this.tput) return this.put.ri();
- return this._write('\x1bM');
- };
- // ESC E Next Line (NEL is 0x85).
- Program.prototype.nextLine = function() {
- this.y++;
- this.x = 0;
- this._ncoords();
- if (this.has('nel')) return this.put.nel();
- return this._write('\x1bE');
- };
- // ESC c Full Reset (RIS).
- Program.prototype.reset = function() {
- this.x = this.y = 0;
- if (this.has('rs1') || this.has('ris')) {
- return this.has('rs1')
- ? this.put.rs1()
- : this.put.ris();
- }
- return this._write('\x1bc');
- };
- // ESC H Tab Set (HTS is 0x88).
- Program.prototype.tabSet = function() {
- if (this.tput) return this.put.hts();
- return this._write('\x1bH');
- };
- // ESC 7 Save Cursor (DECSC).
- Program.prototype.sc =
- Program.prototype.saveCursor = function(key) {
- if (key) return this.lsaveCursor(key);
- this.savedX = this.x || 0;
- this.savedY = this.y || 0;
- if (this.tput) return this.put.sc();
- return this._write('\x1b7');
- };
- // ESC 8 Restore Cursor (DECRC).
- Program.prototype.rc =
- Program.prototype.restoreCursor = function(key, hide) {
- if (key) return this.lrestoreCursor(key, hide);
- this.x = this.savedX || 0;
- this.y = this.savedY || 0;
- if (this.tput) return this.put.rc();
- return this._write('\x1b8');
- };
- // Save Cursor Locally
- Program.prototype.lsaveCursor = function(key) {
- key = key || 'local';
- this._saved = this._saved || {};
- this._saved[key] = this._saved[key] || {};
- this._saved[key].x = this.x;
- this._saved[key].y = this.y;
- this._saved[key].hidden = this.cursorHidden;
- };
- // Restore Cursor Locally
- Program.prototype.lrestoreCursor = function(key, hide) {
- var pos;
- key = key || 'local';
- if (!this._saved || !this._saved[key]) return;
- pos = this._saved[key];
- //delete this._saved[key];
- this.cup(pos.y, pos.x);
- if (hide && pos.hidden !== this.cursorHidden) {
- if (pos.hidden) {
- this.hideCursor();
- } else {
- this.showCursor();
- }
- }
- };
- // ESC # 3 DEC line height/width
- Program.prototype.lineHeight = function() {
- return this._write('\x1b#');
- };
- // ESC (,),*,+,-,. Designate G0-G2 Character Set.
- Program.prototype.charset = function(val, level) {
- level = level || 0;
- // See also:
- // acs_chars / acsc / ac
- // enter_alt_charset_mode / smacs / as
- // exit_alt_charset_mode / rmacs / ae
- // enter_pc_charset_mode / smpch / S2
- // exit_pc_charset_mode / rmpch / S3
- switch (level) {
- case 0:
- level = '(';
- break;
- case 1:
- level = ')';
- break;
- case 2:
- level = '*';
- break;
- case 3:
- level = '+';
- break;
- }
- var name = typeof val === 'string'
- ? val.toLowerCase()
- : val;
- switch (name) {
- case 'acs':
- case 'scld': // DEC Special Character and Line Drawing Set.
- if (this.tput) return this.put.smacs();
- val = '0';
- break;
- case 'uk': // UK
- val = 'A';
- break;
- case 'us': // United States (USASCII).
- case 'usascii':
- case 'ascii':
- if (this.tput) return this.put.rmacs();
- val = 'B';
- break;
- case 'dutch': // Dutch
- val = '4';
- break;
- case 'finnish': // Finnish
- val = 'C';
- val = '5';
- break;
- case 'french': // French
- val = 'R';
- break;
- case 'frenchcanadian': // FrenchCanadian
- val = 'Q';
- break;
- case 'german': // German
- val = 'K';
- break;
- case 'italian': // Italian
- val = 'Y';
- break;
- case 'norwegiandanish': // NorwegianDanish
- val = 'E';
- val = '6';
- break;
- case 'spanish': // Spanish
- val = 'Z';
- break;
- case 'swedish': // Swedish
- val = 'H';
- val = '7';
- break;
- case 'swiss': // Swiss
- val = '=';
- break;
- case 'isolatin': // ISOLatin (actually /A)
- val = '/A';
- break;
- default: // Default
- if (this.tput) return this.put.rmacs();
- val = 'B';
- break;
- }
- return this._write('\x1b(' + val);
- };
- Program.prototype.enter_alt_charset_mode =
- Program.prototype.as =
- Program.prototype.smacs = function() {
- return this.charset('acs');
- };
- Program.prototype.exit_alt_charset_mode =
- Program.prototype.ae =
- Program.prototype.rmacs = function() {
- return this.charset('ascii');
- };
- // ESC N
- // Single Shift Select of G2 Character Set
- // ( SS2 is 0x8e). This affects next character only.
- // ESC O
- // Single Shift Select of G3 Character Set
- // ( SS3 is 0x8f). This affects next character only.
- // ESC n
- // Invoke the G2 Character Set as GL (LS2).
- // ESC o
- // Invoke the G3 Character Set as GL (LS3).
- // ESC |
- // Invoke the G3 Character Set as GR (LS3R).
- // ESC }
- // Invoke the G2 Character Set as GR (LS2R).
- // ESC ~
- // Invoke the G1 Character Set as GR (LS1R).
- Program.prototype.setG = function(val) {
- // if (this.tput) return this.put.S2();
- // if (this.tput) return this.put.S3();
- switch (val) {
- case 1:
- val = '~'; // GR
- break;
- case 2:
- val = 'n'; // GL
- val = '}'; // GR
- val = 'N'; // Next Char Only
- break;
- case 3:
- val = 'o'; // GL
- val = '|'; // GR
- val = 'O'; // Next Char Only
- break;
- }
- return this._write('\x1b' + val);
- };
- /**
- * OSC
- */
- // OSC Ps ; Pt ST
- // OSC Ps ; Pt BEL
- // Set Text Parameters.
- Program.prototype.setTitle = function(title) {
- this._title = title;
- // if (this.term('screen')) {
- // // Tmux pane
- // // if (this.tmux) {
- // // return this._write('\x1b]2;' + title + '\x1b\\');
- // // }
- // return this._write('\x1bk' + title + '\x1b\\');
- // }
- return this._twrite('\x1b]0;' + title + '\x07');
- };
- // OSC Ps ; Pt ST
- // OSC Ps ; Pt BEL
- // Reset colors
- Program.prototype.resetColors = function(param) {
- if (this.has('Cr')) {
- return this.put.Cr(param);
- }
- return this._twrite('\x1b]112\x07');
- //return this._twrite('\x1b]112;' + param + '\x07');
- };
- // OSC Ps ; Pt ST
- // OSC Ps ; Pt BEL
- // Change dynamic colors
- Program.prototype.dynamicColors = function(param) {
- if (this.has('Cs')) {
- return this.put.Cs(param);
- }
- return this._twrite('\x1b]12;' + param + '\x07');
- };
- // OSC Ps ; Pt ST
- // OSC Ps ; Pt BEL
- // Sel data
- Program.prototype.selData = function(a, b) {
- if (this.has('Ms')) {
- return this.put.Ms(a, b);
- }
- return this._twrite('\x1b]52;' + a + ';' + b + '\x07');
- };
- /**
- * CSI
- */
- // CSI Ps A
- // Cursor Up Ps Times (default = 1) (CUU).
- Program.prototype.cuu =
- Program.prototype.up =
- Program.prototype.cursorUp = function(param) {
- this.y -= param || 1;
- this._ncoords();
- if (this.tput) {
- if (!this.tput.strings.parm_up_cursor) {
- return this._write(this.repeat(this.tput.cuu1(), param));
- }
- return this.put.cuu(param);
- }
- return this._write('\x1b[' + (param || '') + 'A');
- };
- // CSI Ps B
- // Cursor Down Ps Times (default = 1) (CUD).
- Program.prototype.cud =
- Program.prototype.down =
- Program.prototype.cursorDown = function(param) {
- this.y += param || 1;
- this._ncoords();
- if (this.tput) {
- if (!this.tput.strings.parm_down_cursor) {
- return this._write(this.repeat(this.tput.cud1(), param));
- }
- return this.put.cud(param);
- }
- return this._write('\x1b[' + (param || '') + 'B');
- };
- // CSI Ps C
- // Cursor Forward Ps Times (default = 1) (CUF).
- Program.prototype.cuf =
- Program.prototype.right =
- Program.prototype.forward =
- Program.prototype.cursorForward = function(param) {
- this.x += param || 1;
- this._ncoords();
- if (this.tput) {
- if (!this.tput.strings.parm_right_cursor) {
- return this._write(this.repeat(this.tput.cuf1(), param));
- }
- return this.put.cuf(param);
- }
- return this._write('\x1b[' + (param || '') + 'C');
- };
- // CSI Ps D
- // Cursor Backward Ps Times (default = 1) (CUB).
- Program.prototype.cub =
- Program.prototype.left =
- Program.prototype.back =
- Program.prototype.cursorBackward = function(param) {
- this.x -= param || 1;
- this._ncoords();
- if (this.tput) {
- if (!this.tput.strings.parm_left_cursor) {
- return this._write(this.repeat(this.tput.cub1(), param));
- }
- return this.put.cub(param);
- }
- return this._write('\x1b[' + (param || '') + 'D');
- };
- // CSI Ps ; Ps H
- // Cursor Position [row;column] (default = [1,1]) (CUP).
- Program.prototype.cup =
- Program.prototype.pos =
- Program.prototype.cursorPos = function(row, col) {
- if (!this.zero) {
- row = (row || 1) - 1;
- col = (col || 1) - 1;
- } else {
- row = row || 0;
- col = col || 0;
- }
- this.x = col;
- this.y = row;
- this._ncoords();
- if (this.tput) return this.put.cup(row, col);
- return this._write('\x1b[' + (row + 1) + ';' + (col + 1) + 'H');
- };
- // CSI Ps J Erase in Display (ED).
- // Ps = 0 -> Erase Below (default).
- // Ps = 1 -> Erase Above.
- // Ps = 2 -> Erase All.
- // Ps = 3 -> Erase Saved Lines (xterm).
- // CSI ? Ps J
- // Erase in Display (DECSED).
- // Ps = 0 -> Selective Erase Below (default).
- // Ps = 1 -> Selective Erase Above.
- // Ps = 2 -> Selective Erase All.
- Program.prototype.ed =
- Program.prototype.eraseInDisplay = function(param) {
- if (this.tput) {
- switch (param) {
- case 'above':
- param = 1;
- break;
- case 'all':
- param = 2;
- break;
- case 'saved':
- param = 3;
- break;
- case 'below':
- default:
- param = 0;
- break;
- }
- // extended tput.E3 = ^[[3;J
- return this.put.ed(param);
- }
- switch (param) {
- case 'above':
- return this._write('\X1b[1J');
- case 'all':
- return this._write('\x1b[2J');
- case 'saved':
- return this._write('\x1b[3J');
- case 'below':
- default:
- return this._write('\x1b[J');
- }
- };
- Program.prototype.clear = function() {
- this.x = 0;
- this.y = 0;
- if (this.tput) return this.put.clear();
- return this._write('\x1b[H\x1b[J');
- };
- // CSI Ps K Erase in Line (EL).
- // Ps = 0 -> Erase to Right (default).
- // Ps = 1 -> Erase to Left.
- // Ps = 2 -> Erase All.
- // CSI ? Ps K
- // Erase in Line (DECSEL).
- // Ps = 0 -> Selective Erase to Right (default).
- // Ps = 1 -> Selective Erase to Left.
- // Ps = 2 -> Selective Erase All.
- Program.prototype.el =
- Program.prototype.eraseInLine = function(param) {
- if (this.tput) {
- //if (this.tput.back_color_erase) ...
- switch (param) {
- case 'left':
- param = 1;
- break;
- case 'all':
- param = 2;
- break;
- case 'right':
- default:
- param = 0;
- break;
- }
- return this.put.el(param);
- }
- switch (param) {
- case 'left':
- return this._write('\x1b[1K');
- case 'all':
- return this._write('\x1b[2K');
- case 'right':
- default:
- return this._write('\x1b[K');
- }
- };
- // CSI Pm m Character Attributes (SGR).
- // Ps = 0 -> Normal (default).
- // Ps = 1 -> Bold.
- // Ps = 4 -> Underlined.
- // Ps = 5 -> Blink (appears as Bold).
- // Ps = 7 -> Inverse.
- // Ps = 8 -> Invisible, i.e., hidden (VT300).
- // Ps = 2 2 -> Normal (neither bold nor faint).
- // Ps = 2 4 -> Not underlined.
- // Ps = 2 5 -> Steady (not blinking).
- // Ps = 2 7 -> Positive (not inverse).
- // Ps = 2 8 -> Visible, i.e., not hidden (VT300).
- // Ps = 3 0 -> Set foreground color to Black.
- // Ps = 3 1 -> Set foreground color to Red.
- // Ps = 3 2 -> Set foreground color to Green.
- // Ps = 3 3 -> Set foreground color to Yellow.
- // Ps = 3 4 -> Set foreground color to Blue.
- // Ps = 3 5 -> Set foreground color to Magenta.
- // Ps = 3 6 -> Set foreground color to Cyan.
- // Ps = 3 7 -> Set foreground color to White.
- // Ps = 3 9 -> Set foreground color to default (original).
- // Ps = 4 0 -> Set background color to Black.
- // Ps = 4 1 -> Set background color to Red.
- // Ps = 4 2 -> Set background color to Green.
- // Ps = 4 3 -> Set background color to Yellow.
- // Ps = 4 4 -> Set background color to Blue.
- // Ps = 4 5 -> Set background color to Magenta.
- // Ps = 4 6 -> Set background color to Cyan.
- // Ps = 4 7 -> Set background color to White.
- // Ps = 4 9 -> Set background color to default (original).
- // If 16-color support is compiled, the following apply. Assume
- // that xterm's resources are set so that the ISO color codes are
- // the first 8 of a set of 16. Then the aixterm colors are the
- // bright versions of the ISO colors:
- // Ps = 9 0 -> Set foreground color to Black.
- // Ps = 9 1 -> Set foreground color to Red.
- // Ps = 9 2 -> Set foreground color to Green.
- // Ps = 9 3 -> Set foreground color to Yellow.
- // Ps = 9 4 -> Set foreground color to Blue.
- // Ps = 9 5 -> Set foreground color to Magenta.
- // Ps = 9 6 -> Set foreground color to Cyan.
- // Ps = 9 7 -> Set foreground color to White.
- // Ps = 1 0 0 -> Set background color to Black.
- // Ps = 1 0 1 -> Set background color to Red.
- // Ps = 1 0 2 -> Set background color to Green.
- // Ps = 1 0 3 -> Set background color to Yellow.
- // Ps = 1 0 4 -> Set background color to Blue.
- // Ps = 1 0 5 -> Set background color to Magenta.
- // Ps = 1 0 6 -> Set background color to Cyan.
- // Ps = 1 0 7 -> Set background color to White.
- // If xterm is compiled with the 16-color support disabled, it
- // supports the following, from rxvt:
- // Ps = 1 0 0 -> Set foreground and background color to
- // default.
- // If 88- or 256-color support is compiled, the following apply.
- // Ps = 3 8 ; 5 ; Ps -> Set foreground color to the second
- // Ps.
- // Ps = 4 8 ; 5 ; Ps -> Set background color to the second
- // Ps.
- Program.prototype.sgr =
- Program.prototype.attr =
- Program.prototype.charAttributes = function(param, val) {
- return this._write(this._attr(param, val));
- };
- Program.prototype.text = function(text, attr) {
- return this._attr(attr, true) + text + this._attr(attr, false);
- };
- // NOTE: sun-color may not allow multiple params for SGR.
- Program.prototype._attr = function(param, val) {
- var self = this
- , parts
- , color
- , m;
- if (Array.isArray(param)) {
- parts = param;
- param = parts[0] || 'normal';
- } else {
- param = param || 'normal';
- parts = param.split(/\s*[,;]\s*/);
- }
- if (parts.length > 1) {
- var used = {}
- , out = [];
- parts.forEach(function(part) {
- part = self._attr(part, val).slice(2, -1);
- if (part === '') return;
- if (used[part]) return;
- used[part] = true;
- out.push(part);
- });
- return '\x1b[' + out.join(';') + 'm';
- }
- if (param.indexOf('no ') === 0) {
- param = param.substring(3);
- val = false;
- } else if (param.indexOf('!') === 0) {
- param = param.substring(1);
- val = false;
- }
- switch (param) {
- // attributes
- case 'normal':
- case 'default':
- if (val === false) return '';
- return '\x1b[m';
- case 'bold':
- return val === false
- ? '\x1b[22m'
- : '\x1b[1m';
- case 'ul':
- case 'underline':
- case 'underlined':
- return val === false
- ? '\x1b[24m'
- : '\x1b[4m';
- case 'blink':
- return val === false
- ? '\x1b[25m'
- : '\x1b[5m';
- case 'inverse':
- return val === false
- ? '\x1b[27m'
- : '\x1b[7m';
- case 'invisible':
- return val === false
- ? '\x1b[28m'
- : '\x1b[8m';
- // 8-color foreground
- case 'black fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[30m';
- case 'red fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[31m';
- case 'green fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[32m';
- case 'yellow fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[33m';
- case 'blue fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[34m';
- case 'magenta fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[35m';
- case 'cyan fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[36m';
- case 'white fg':
- case 'light grey fg':
- case 'light gray fg':
- case 'bright grey fg':
- case 'bright gray fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[37m';
- case 'default fg':
- if (val === false) return '';
- return '\x1b[39m';
- // 8-color background
- case 'black bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[40m';
- case 'red bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[41m';
- case 'green bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[42m';
- case 'yellow bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[43m';
- case 'blue bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[44m';
- case 'magenta bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[45m';
- case 'cyan bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[46m';
- case 'white bg':
- case 'light grey bg':
- case 'light gray bg':
- case 'bright grey bg':
- case 'bright gray bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[47m';
- case 'default bg':
- if (val === false) return '';
- return '\x1b[49m';
- // 16-color foreground
- case 'light black fg':
- case 'bright black fg':
- case 'grey fg':
- case 'gray fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[90m';
- case 'light red fg':
- case 'bright red fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[91m';
- case 'light green fg':
- case 'bright green fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[92m';
- case 'light yellow fg':
- case 'bright yellow fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[93m';
- case 'light blue fg':
- case 'bright blue fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[94m';
- case 'light magenta fg':
- case 'bright magenta fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[95m';
- case 'light cyan fg':
- case 'bright cyan fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[96m';
- case 'light white fg':
- case 'bright white fg':
- return val === false
- ? '\x1b[39m'
- : '\x1b[97m';
- // 16-color background
- case 'light black bg':
- case 'bright black bg':
- case 'grey bg':
- case 'gray bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[100m';
- case 'light red bg':
- case 'bright red bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[101m';
- case 'light green bg':
- case 'bright green bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[102m';
- case 'light yellow bg':
- case 'bright yellow bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[103m';
- case 'light blue bg':
- case 'bright blue bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[104m';
- case 'light magenta bg':
- case 'bright magenta bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[105m';
- case 'light cyan bg':
- case 'bright cyan bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[106m';
- case 'light white bg':
- case 'bright white bg':
- return val === false
- ? '\x1b[49m'
- : '\x1b[107m';
- // non-16-color rxvt default fg and bg
- case 'default fg bg':
- if (val === false) return '';
- return this.term('rxvt')
- ? '\x1b[100m'
- : '\x1b[39;49m';
- default:
- // 256-color fg and bg
- if (param[0] === '#') {
- param = param.replace(/#(?:[0-9a-f]{3}){1,2}/i, colors.match);
- }
- m = /^(-?\d+) (fg|bg)$/.exec(param);
- if (m) {
- color = +m[1];
- if (val === false || color === -1) {
- return this._attr('default ' + m[2]);
- }
- color = colors.reduce(color, this.tput.colors);
- if (color < 16 || (this.tput && this.tput.colors <= 16)) {
- if (m[2] === 'fg') {
- if (color < 8) {
- color += 30;
- } else if (color < 16) {
- color -= 8;
- color += 90;
- }
- } else if (m[2] === 'bg') {
- if (color < 8) {
- color += 40;
- } else if (color < 16) {
- color -= 8;
- color += 100;
- }
- }
- return '\x1b[' + color + 'm';
- }
- if (m[2] === 'fg') {
- return '\x1b[38;5;' + color + 'm';
- }
- if (m[2] === 'bg') {
- return '\x1b[48;5;' + color + 'm';
- }
- }
- if (/^[\d;]*$/.test(param)) {
- return '\x1b[' + param + 'm';
- }
- return null;
- }
- };
- Program.prototype.fg =
- Program.prototype.setForeground = function(color, val) {
- color = color.split(/\s*[,;]\s*/).join(' fg, ') + ' fg';
- return this.attr(color, val);
- };
- Program.prototype.bg =
- Program.prototype.setBackground = function(color, val) {
- color = color.split(/\s*[,;]\s*/).join(' bg, ') + ' bg';
- return this.attr(color, val);
- };
- // CSI Ps n Device Status Report (DSR).
- // Ps = 5 -> Status Report. Result (``OK'') is
- // CSI 0 n
- // Ps = 6 -> Report Cursor Position (CPR) [row;column].
- // Result is
- // CSI r ; c R
- // CSI ? Ps n
- // Device Status Report (DSR, DEC-specific).
- // Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI
- // ? r ; c R (assumes page is zero).
- // Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready).
- // or CSI ? 1 1 n (not ready).
- // Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked)
- // or CSI ? 2 1 n (locked).
- // Ps = 2 6 -> Report Keyboard status as
- // CSI ? 2 7 ; 1 ; 0 ; 0 n (North American).
- // The last two parameters apply to VT400 & up, and denote key-
- // board ready and LK01 respectively.
- // Ps = 5 3 -> Report Locator status as
- // CSI ? 5 3 n Locator available, if compiled-in, or
- // CSI ? 5 0 n No Locator, if not.
- Program.prototype.dsr =
- Program.prototype.deviceStatus = function(param, callback, dec, noBypass) {
- if (dec) {
- return this.response('device-status',
- '\x1b[?' + (param || '0') + 'n', callback, noBypass);
- }
- return this.response('device-status',
- '\x1b[' + (param || '0') + 'n', callback, noBypass);
- };
- Program.prototype.getCursor = function(callback) {
- return this.deviceStatus(6, callback, false, true);
- };
- Program.prototype.saveReportedCursor = function(callback) {
- var self = this;
- if (this.tput.strings.user7 === '\x1b[6n' || this.term('screen')) {
- return this.getCursor(function(err, data) {
- if (data) {
- self._rx = data.status.x;
- self._ry = data.status.y;
- }
- if (!callback) return;
- return callback(err);
- });
- }
- if (!callback) return;
- return callback();
- };
- Program.prototype.restoreReportedCursor = function() {
- if (this._rx == null) return;
- return this.cup(this._ry, this._rx);
- // return this.nel();
- };
- /**
- * Additions
- */
- // CSI Ps @
- // Insert Ps (Blank) Character(s) (default = 1) (ICH).
- Program.prototype.ich =
- Program.prototype.insertChars = function(param) {
- this.x += param || 1;
- this._ncoords();
- if (this.tput) return this.put.ich(param);
- return this._write('\x1b[' + (param || 1) + '@');
- };
- // CSI Ps E
- // Cursor Next Line Ps Times (default = 1) (CNL).
- // same as CSI Ps B ?
- Program.prototype.cnl =
- Program.prototype.cursorNextLine = function(param) {
- this.y += param || 1;
- this._ncoords();
- return this._write('\x1b[' + (param || '') + 'E');
- };
- // CSI Ps F
- // Cursor Preceding Line Ps Times (default = 1) (CNL).
- // reuse CSI Ps A ?
- Program.prototype.cpl =
- Program.prototype.cursorPrecedingLine = function(param) {
- this.y -= param || 1;
- this._ncoords();
- return this._write('\x1b[' + (param || '') + 'F');
- };
- // CSI Ps G
- // Cursor Character Absolute [column] (default = [row,1]) (CHA).
- Program.prototype.cha =
- Program.prototype.cursorCharAbsolute = function(param) {
- if (!this.zero) {
- param = (param || 1) - 1;
- } else {
- param = param || 0;
- }
- this.x = param;
- this.y = 0;
- this._ncoords();
- if (this.tput) return this.put.hpa(param);
- return this._write('\x1b[' + (param + 1) + 'G');
- };
- // CSI Ps L
- // Insert Ps Line(s) (default = 1) (IL).
- Program.prototype.il =
- Program.prototype.insertLines = function(param) {
- if (this.tput) return this.put.il(param);
- return this._write('\x1b[' + (param || '') + 'L');
- };
- // CSI Ps M
- // Delete Ps Line(s) (default = 1) (DL).
- Program.prototype.dl =
- Program.prototype.deleteLines = function(param) {
- if (this.tput) return this.put.dl(param);
- return this._write('\x1b[' + (param || '') + 'M');
- };
- // CSI Ps P
- // Delete Ps Character(s) (default = 1) (DCH).
- Program.prototype.dch =
- Program.prototype.deleteChars = function(param) {
- if (this.tput) return this.put.dch(param);
- return this._write('\x1b[' + (param || '') + 'P');
- };
- // CSI Ps X
- // Erase Ps Character(s) (default = 1) (ECH).
- Program.prototype.ech =
- Program.prototype.eraseChars = function(param) {
- if (this.tput) return this.put.ech(param);
- return this._write('\x1b[' + (param || '') + 'X');
- };
- // CSI Pm ` Character Position Absolute
- // [column] (default = [row,1]) (HPA).
- Program.prototype.hpa =
- Program.prototype.charPosAbsolute = function(param) {
- this.x = param || 0;
- this._ncoords();
- if (this.tput) {
- return this.put.hpa.apply(this.put, arguments);
- }
- param = slice.call(arguments).join(';');
- return this._write('\x1b[' + (param || '') + '`');
- };
- // 141 61 a * HPR -
- // Horizontal Position Relative
- // reuse CSI Ps C ?
- Program.prototype.hpr =
- Program.prototype.HPositionRelative = function(param) {
- if (this.tput) return this.cuf(param);
- this.x += param || 1;
- this._ncoords();
- // Does not exist:
- // if (this.tput) return this.put.hpr(param);
- return this._write('\x1b[' + (param || '') + 'a');
- };
- // CSI Ps c Send Device Attributes (Primary DA).
- // Ps = 0 or omitted -> request attributes from terminal. The
- // response depends on the decTerminalID resource setting.
- // -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'')
- // -> CSI ? 1 ; 0 c (``VT101 with No Options'')
- // -> CSI ? 6 c (``VT102'')
- // -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'')
- // The VT100-style response parameters do not mean anything by
- // themselves. VT220 parameters do, telling the host what fea-
- // tures the terminal supports:
- // Ps = 1 -> 132-columns.
- // Ps = 2 -> Printer.
- // Ps = 6 -> Selective erase.
- // Ps = 8 -> User-defined keys.
- // Ps = 9 -> National replacement character sets.
- // Ps = 1 5 -> Technical characters.
- // Ps = 2 2 -> ANSI color, e.g., VT525.
- // Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode).
- // CSI > Ps c
- // Send Device Attributes (Secondary DA).
- // Ps = 0 or omitted -> request the terminal's identification
- // code. The response depends on the decTerminalID resource set-
- // ting. It should apply only to VT220 and up, but xterm extends
- // this to VT100.
- // -> CSI > Pp ; Pv ; Pc c
- // where Pp denotes the terminal type
- // Pp = 0 -> ``VT100''.
- // Pp = 1 -> ``VT220''.
- // and Pv is the firmware version (for xterm, this was originally
- // the XFree86 patch number, starting with 95). In a DEC termi-
- // nal, Pc indicates the ROM cartridge registration number and is
- // always zero.
- // More information:
- // xterm/charproc.c - line 2012, for more information.
- // vim responds with ^[[?0c or ^[[?1c after the terminal's response (?)
- Program.prototype.da =
- Program.prototype.sendDeviceAttributes = function(param, callback) {
- return this.response('device-attributes',
- '\x1b[' + (param || '') + 'c', callback);
- };
- // CSI Pm d
- // Line Position Absolute [row] (default = [1,column]) (VPA).
- // NOTE: Can't find in terminfo, no idea why it has multiple params.
- Program.prototype.vpa =
- Program.prototype.linePosAbsolute = function(param) {
- this.y = param || 1;
- this._ncoords();
- if (this.tput) {
- return this.put.vpa.apply(this.put, arguments);
- }
- param = slice.call(arguments).join(';');
- return this._write('\x1b[' + (param || '') + 'd');
- };
- // 145 65 e * VPR - Vertical Position Relative
- // reuse CSI Ps B ?
- Program.prototype.vpr =
- Program.prototype.VPositionRelative = function(param) {
- if (this.tput) return this.cud(param);
- this.y += param || 1;
- this._ncoords();
- // Does not exist:
- // if (this.tput) return this.put.vpr(param);
- return this._write('\x1b[' + (param || '') + 'e');
- };
- // CSI Ps ; Ps f
- // Horizontal and Vertical Position [row;column] (default =
- // [1,1]) (HVP).
- Program.prototype.hvp =
- Program.prototype.HVPosition = function(row, col) {
- if (!this.zero) {
- row = (row || 1) - 1;
- col = (col || 1) - 1;
- } else {
- row = row || 0;
- col = col || 0;
- }
- this.y = row;
- this.x = col;
- this._ncoords();
- // Does not exist (?):
- // if (this.tput) return this.put.hvp(row, col);
- if (this.tput) return this.put.cup(row, col);
- return this._write('\x1b[' + (row + 1) + ';' + (col + 1) + 'f');
- };
- // CSI Pm h Set Mode (SM).
- // Ps = 2 -> Keyboard Action Mode (AM).
- // Ps = 4 -> Insert Mode (IRM).
- // Ps = 1 2 -> Send/receive (SRM).
- // Ps = 2 0 -> Automatic Newline (LNM).
- // CSI ? Pm h
- // DEC Private Mode Set (DECSET).
- // Ps = 1 -> Application Cursor Keys (DECCKM).
- // Ps = 2 -> Designate USASCII for character sets G0-G3
- // (DECANM), and set VT100 mode.
- // Ps = 3 -> 132 Column Mode (DECCOLM).
- // Ps = 4 -> Smooth (Slow) Scroll (DECSCLM).
- // Ps = 5 -> Reverse Video (DECSCNM).
- // Ps = 6 -> Origin Mode (DECOM).
- // Ps = 7 -> Wraparound Mode (DECAWM).
- // Ps = 8 -> Auto-repeat Keys (DECARM).
- // Ps = 9 -> Send Mouse X & Y on button press. See the sec-
- // tion Mouse Tracking.
- // Ps = 1 0 -> Show toolbar (rxvt).
- // Ps = 1 2 -> Start Blinking Cursor (att610).
- // Ps = 1 8 -> Print form feed (DECPFF).
- // Ps = 1 9 -> Set print extent to full screen (DECPEX).
- // Ps = 2 5 -> Show Cursor (DECTCEM).
- // Ps = 3 0 -> Show scrollbar (rxvt).
- // Ps = 3 5 -> Enable font-shifting functions (rxvt).
- // Ps = 3 8 -> Enter Tektronix Mode (DECTEK).
- // Ps = 4 0 -> Allow 80 -> 132 Mode.
- // Ps = 4 1 -> more(1) fix (see curses resource).
- // Ps = 4 2 -> Enable Nation Replacement Character sets (DECN-
- // RCM).
- // Ps = 4 4 -> Turn On Margin Bell.
- // Ps = 4 5 -> Reverse-wraparound Mode.
- // Ps = 4 6 -> Start Logging. This is normally disabled by a
- // compile-time option.
- // Ps = 4 7 -> Use Alternate Screen Buffer. (This may be dis-
- // abled by the titeInhibit resource).
- // Ps = 6 6 -> Application keypad (DECNKM).
- // Ps = 6 7 -> Backarrow key sends backspace (DECBKM).
- // Ps = 1 0 0 0 -> Send Mouse X & Y on button press and
- // release. See the section Mouse Tracking.
- // Ps = 1 0 0 1 -> Use Hilite Mouse Tracking.
- // Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking.
- // Ps = 1 0 0 3 -> Use All Motion Mouse Tracking.
- // Ps = 1 0 0 4 -> Send FocusIn/FocusOut events.
- // Ps = 1 0 0 5 -> Enable Extended Mouse Mode.
- // Ps = 1 0 1 0 -> Scroll to bottom on tty output (rxvt).
- // Ps = 1 0 1 1 -> Scroll to bottom on key press (rxvt).
- // Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit.
- // (enables the eightBitInput resource).
- // Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num-
- // Lock keys. (This enables the numLock resource).
- // Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This
- // enables the metaSendsEscape resource).
- // Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete
- // key.
- // Ps = 1 0 3 9 -> Send ESC when Alt modifies a key. (This
- // enables the altSendsEscape resource).
- // Ps = 1 0 4 0 -> Keep selection even if not highlighted.
- // (This enables the keepSelection resource).
- // Ps = 1 0 4 1 -> Use the CLIPBOARD selection. (This enables
- // the selectToClipboard resource).
- // Ps = 1 0 4 2 -> Enable Urgency window manager hint when
- // Control-G is received. (This enables the bellIsUrgent
- // resource).
- // Ps = 1 0 4 3 -> Enable raising of the window when Control-G
- // is received. (enables the popOnBell resource).
- // Ps = 1 0 4 7 -> Use Alternate Screen Buffer. (This may be
- // disabled by the titeInhibit resource).
- // Ps = 1 0 4 8 -> Save cursor as in DECSC. (This may be dis-
- // abled by the titeInhibit resource).
- // Ps = 1 0 4 9 -> Save cursor as in DECSC and use Alternate
- // Screen Buffer, clearing it first. (This may be disabled by
- // the titeInhibit resource). This combines the effects of the 1
- // 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based
- // applications rather than the 4 7 mode.
- // Ps = 1 0 5 0 -> Set terminfo/termcap function-key mode.
- // Ps = 1 0 5 1 -> Set Sun function-key mode.
- // Ps = 1 0 5 2 -> Set HP function-key mode.
- // Ps = 1 0 5 3 -> Set SCO function-key mode.
- // Ps = 1 0 6 0 -> Set legacy keyboard emulation (X11R6).
- // Ps = 1 0 6 1 -> Set VT220 keyboard emulation.
- // Ps = 2 0 0 4 -> Set bracketed paste mode.
- // Modes:
- // http://vt100.net/docs/vt220-rm/chapter4.html
- Program.prototype.sm =
- Program.prototype.setMode = function() {
- var param = slice.call(arguments).join(';');
- return this._write('\x1b[' + (param || '') + 'h');
- };
- Program.prototype.decset = function() {
- var param = slice.call(arguments).join(';');
- return this.setMode('?' + param);
- };
- Program.prototype.dectcem =
- Program.prototype.cnorm =
- Program.prototype.cvvis =
- Program.prototype.showCursor = function() {
- this.cursorHidden = false;
- // NOTE: In xterm terminfo:
- // cnorm stops blinking cursor
- // cvvis starts blinking cursor
- if (this.tput) return this.put.cnorm();
- //if (this.tput) return this.put.cvvis();
- // return this._write('\x1b[?12l\x1b[?25h'); // cursor_normal
- // return this._write('\x1b[?12;25h'); // cursor_visible
- return this.setMode('?25');
- };
- Program.prototype.alternate =
- Program.prototype.smcup =
- Program.prototype.alternateBuffer = function() {
- this.isAlt = true;
- if (this.tput) return this.put.smcup();
- if (this.term('vt') || this.term('linux')) return;
- this.setMode('?47');
- return this.setMode('?1049');
- };
- // CSI Pm l Reset Mode (RM).
- // Ps = 2 -> Keyboard Action Mode (AM).
- // Ps = 4 -> Replace Mode (IRM).
- // Ps = 1 2 -> Send/receive (SRM).
- // Ps = 2 0 -> Normal Linefeed (LNM).
- // CSI ? Pm l
- // DEC Private Mode Reset (DECRST).
- // Ps = 1 -> Normal Cursor Keys (DECCKM).
- // Ps = 2 -> Designate VT52 mode (DECANM).
- // Ps = 3 -> 80 Column Mode (DECCOLM).
- // Ps = 4 -> Jump (Fast) Scroll (DECSCLM).
- // Ps = 5 -> Normal Video (DECSCNM).
- // Ps = 6 -> Normal Cursor Mode (DECOM).
- // Ps = 7 -> No Wraparound Mode (DECAWM).
- // Ps = 8 -> No Auto-repeat Keys (DECARM).
- // Ps = 9 -> Don't send Mouse X & Y on button press.
- // Ps = 1 0 -> Hide toolbar (rxvt).
- // Ps = 1 2 -> Stop Blinking Cursor (att610).
- // Ps = 1 8 -> Don't print form feed (DECPFF).
- // Ps = 1 9 -> Limit print to scrolling region (DECPEX).
- // Ps = 2 5 -> Hide Cursor (DECTCEM).
- // Ps = 3 0 -> Don't show scrollbar (rxvt).
- // Ps = 3 5 -> Disable font-shifting functions (rxvt).
- // Ps = 4 0 -> Disallow 80 -> 132 Mode.
- // Ps = 4 1 -> No more(1) fix (see curses resource).
- // Ps = 4 2 -> Disable Nation Replacement Character sets (DEC-
- // NRCM).
- // Ps = 4 4 -> Turn Off Margin Bell.
- // Ps = 4 5 -> No Reverse-wraparound Mode.
- // Ps = 4 6 -> Stop Logging. (This is normally disabled by a
- // compile-time option).
- // Ps = 4 7 -> Use Normal Screen Buffer.
- // Ps = 6 6 -> Numeric keypad (DECNKM).
- // Ps = 6 7 -> Backarrow key sends delete (DECBKM).
- // Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and
- // release. See the section Mouse Tracking.
- // Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking.
- // Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking.
- // Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking.
- // Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events.
- // Ps = 1 0 0 5 -> Disable Extended Mouse Mode.
- // Ps = 1 0 1 0 -> Don't scroll to bottom on tty output
- // (rxvt).
- // Ps = 1 0 1 1 -> Don't scroll to bottom on key press (rxvt).
- // Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables
- // the eightBitInput resource).
- // Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num-
- // Lock keys. (This disables the numLock resource).
- // Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key.
- // (This disables the metaSendsEscape resource).
- // Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad
- // Delete key.
- // Ps = 1 0 3 9 -> Don't send ESC when Alt modifies a key.
- // (This disables the altSendsEscape resource).
- // Ps = 1 0 4 0 -> Do not keep selection when not highlighted.
- // (This disables the keepSelection resource).
- // Ps = 1 0 4 1 -> Use the PRIMARY selection. (This disables
- // the selectToClipboard resource).
- // Ps = 1 0 4 2 -> Disable Urgency window manager hint when
- // Control-G is received. (This disables the bellIsUrgent
- // resource).
- // Ps = 1 0 4 3 -> Disable raising of the window when Control-
- // G is received. (This disables the popOnBell resource).
- // Ps = 1 0 4 7 -> Use Normal Screen Buffer, clearing screen
- // first if in the Alternate Screen. (This may be disabled by
- // the titeInhibit resource).
- // Ps = 1 0 4 8 -> Restore cursor as in DECRC. (This may be
- // disabled by the titeInhibit resource).
- // Ps = 1 0 4 9 -> Use Normal Screen Buffer and restore cursor
- // as in DECRC. (This may be disabled by the titeInhibit
- // resource). This combines the effects of the 1 0 4 7 and 1 0
- // 4 8 modes. Use this with terminfo-based applications rather
- // than the 4 7 mode.
- // Ps = 1 0 5 0 -> Reset terminfo/termcap function-key mode.
- // Ps = 1 0 5 1 -> Reset Sun function-key mode.
- // Ps = 1 0 5 2 -> Reset HP function-key mode.
- // Ps = 1 0 5 3 -> Reset SCO function-key mode.
- // Ps = 1 0 6 0 -> Reset legacy keyboard emulation (X11R6).
- // Ps = 1 0 6 1 -> Reset keyboard emulation to Sun/PC style.
- // Ps = 2 0 0 4 -> Reset bracketed paste mode.
- Program.prototype.rm =
- Program.prototype.resetMode = function() {
- var param = slice.call(arguments).join(';');
- return this._write('\x1b[' + (param || '') + 'l');
- };
- Program.prototype.decrst = function() {
- var param = slice.call(arguments).join(';');
- return this.resetMode('?' + param);
- };
- Program.prototype.dectcemh =
- Program.prototype.cursor_invisible =
- Program.prototype.vi =
- Program.prototype.civis =
- Program.prototype.hideCursor = function() {
- this.cursorHidden = true;
- if (this.tput) return this.put.civis();
- return this.resetMode('?25');
- };
- Program.prototype.rmcup =
- Program.prototype.normalBuffer = function() {
- this.isAlt = false;
- if (this.tput) return this.put.rmcup();
- this.resetMode('?47');
- return this.resetMode('?1049');
- };
- Program.prototype.enableMouse = function() {
- if (process.env.BLESSED_FORCE_MODES) {
- var modes = process.env.BLESSED_FORCE_MODES.split(',');
- var options = {};
- for (var n = 0; n < modes.length; ++n) {
- var pair = modes[n].split('=');
- var v = pair[1] !== '0';
- switch (pair[0].toUpperCase()) {
- case 'SGRMOUSE':
- options.sgrMouse = v;
- break;
- case 'UTFMOUSE':
- options.utfMouse = v;
- break;
- case 'VT200MOUSE':
- options.vt200Mouse = v;
- break;
- case 'URXVTMOUSE':
- options.urxvtMouse = v;
- break;
- case 'X10MOUSE':
- options.x10Mouse = v;
- break;
- case 'DECMOUSE':
- options.decMouse = v;
- break;
- case 'PTERMMOUSE':
- options.ptermMouse = v;
- break;
- case 'JSBTERMMOUSE':
- options.jsbtermMouse = v;
- break;
- case 'VT200HILITE':
- options.vt200Hilite = v;
- break;
- case 'GPMMOUSE':
- options.gpmMouse = v;
- break;
- case 'CELLMOTION':
- options.cellMotion = v;
- break;
- case 'ALLMOTION':
- options.allMotion = v;
- break;
- case 'SENDFOCUS':
- options.sendFocus = v;
- break;
- }
- }
- return this.setMouse(options, true);
- }
- // NOTE:
- // Cell Motion isn't normally need for anything below here, but we'll
- // activate it for tmux (whether using it or not) in case our all-motion
- // passthrough does not work. It can't hurt.
- if (this.term('rxvt-unicode')) {
- return this.setMouse({
- urxvtMouse: true,
- cellMotion: true,
- allMotion: true
- }, true);
- }
- // rxvt does not support the X10 UTF extensions
- if (this.term('rxvt')) {
- return this.setMouse({
- vt200Mouse: true,
- x10Mouse: true,
- cellMotion: true,
- allMotion: true
- }, true);
- }
- // libvte is broken. Older versions do not support the
- // X10 UTF extension. However, later versions do support
- // SGR/URXVT.
- if (this.isVTE) {
- return this.setMouse({
- // NOTE: Could also use urxvtMouse here.
- sgrMouse: true,
- cellMotion: true,
- allMotion: true
- }, true);
- }
- if (this.term('linux')) {
- return this.setMouse({
- vt200Mouse: true,
- gpmMouse: true
- }, true);
- }
- if (this.term('xterm')
- || this.term('screen')
- || (this.tput && this.tput.strings.key_mouse)) {
- return this.setMouse({
- vt200Mouse: true,
- utfMouse: true,
- cellMotion: true,
- allMotion: true
- }, true);
- }
- };
- Program.prototype.disableMouse = function() {
- if (!this._currentMouse) return;
- var obj = {};
- Object.keys(this._currentMouse).forEach(function(key) {
- obj[key] = false;
- });
- return this.setMouse(obj, false);
- };
- // Set Mouse
- Program.prototype.setMouse = function(opt, enable) {
- if (opt.normalMouse != null) {
- opt.vt200Mouse = opt.normalMouse;
- opt.allMotion = opt.normalMouse;
- }
- if (opt.hiliteTracking != null) {
- opt.vt200Hilite = opt.hiliteTracking;
- }
- if (enable === true) {
- if (this._currentMouse) {
- this.setMouse(opt);
- Object.keys(opt).forEach(function(key) {
- this._currentMouse[key] = opt[key];
- }, this);
- return;
- }
- this._currentMouse = opt;
- this.mouseEnabled = true;
- } else if (enable === false) {
- delete this._currentMouse;
- this.mouseEnabled = false;
- }
- // Ps = 9 -> Send Mouse X & Y on button press. See the sec-
- // tion Mouse Tracking.
- // Ps = 9 -> Don't send Mouse X & Y on button press.
- // x10 mouse
- if (opt.x10Mouse != null) {
- if (opt.x10Mouse) this.setMode('?9');
- else this.resetMode('?9');
- }
- // Ps = 1 0 0 0 -> Send Mouse X & Y on button press and
- // release. See the section Mouse Tracking.
- // Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and
- // release. See the section Mouse Tracking.
- // vt200 mouse
- if (opt.vt200Mouse != null) {
- if (opt.vt200Mouse) this.setMode('?1000');
- else this.resetMode('?1000');
- }
- // Ps = 1 0 0 1 -> Use Hilite Mouse Tracking.
- // Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking.
- if (opt.vt200Hilite != null) {
- if (opt.vt200Hilite) this.setMode('?1001');
- else this.resetMode('?1001');
- }
- // Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking.
- // Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking.
- // button event mouse
- if (opt.cellMotion != null) {
- if (opt.cellMotion) this.setMode('?1002');
- else this.resetMode('?1002');
- }
- // Ps = 1 0 0 3 -> Use All Motion Mouse Tracking.
- // Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking.
- // any event mouse
- if (opt.allMotion != null) {
- // NOTE: Latest versions of tmux seem to only support cellMotion (not
- // allMotion). We pass all motion through to the terminal.
- if (this.tmux && this.tmuxVersion >= 2) {
- if (opt.allMotion) this._twrite('\x1b[?1003h');
- else this._twrite('\x1b[?1003l');
- } else {
- if (opt.allMotion) this.setMode('?1003');
- else this.resetMode('?1003');
- }
- }
- // Ps = 1 0 0 4 -> Send FocusIn/FocusOut events.
- // Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events.
- if (opt.sendFocus != null) {
- if (opt.sendFocus) this.setMode('?1004');
- else this.resetMode('?1004');
- }
- // Ps = 1 0 0 5 -> Enable Extended Mouse Mode.
- // Ps = 1 0 0 5 -> Disable Extended Mouse Mode.
- if (opt.utfMouse != null) {
- if (opt.utfMouse) this.setMode('?1005');
- else this.resetMode('?1005');
- }
- // sgr mouse
- if (opt.sgrMouse != null) {
- if (opt.sgrMouse) this.setMode('?1006');
- else this.resetMode('?1006');
- }
- // urxvt mouse
- if (opt.urxvtMouse != null) {
- if (opt.urxvtMouse) this.setMode('?1015');
- else this.resetMode('?1015');
- }
- // dec mouse
- if (opt.decMouse != null) {
- if (opt.decMouse) this._write('\x1b[1;2\'z\x1b[1;3\'{');
- else this._write('\x1b[\'z');
- }
- // pterm mouse
- if (opt.ptermMouse != null) {
- if (opt.ptermMouse) this._write('\x1b[>1h\x1b[>6h\x1b[>7h\x1b[>1h\x1b[>9l');
- else this._write('\x1b[>1l\x1b[>6l\x1b[>7l\x1b[>1l\x1b[>9h');
- }
- // jsbterm mouse
- if (opt.jsbtermMouse != null) {
- // + = advanced mode
- if (opt.jsbtermMouse) this._write('\x1b[0~ZwLMRK+1Q\x1b\\');
- else this._write('\x1b[0~ZwQ\x1b\\');
- }
- // gpm mouse
- if (opt.gpmMouse != null) {
- if (opt.gpmMouse) this.enableGpm();
- else this.disableGpm();
- }
- };
- // CSI Ps ; Ps r
- // Set Scrolling Region [top;bottom] (default = full size of win-
- // dow) (DECSTBM).
- // CSI ? Pm r
- Program.prototype.decstbm =
- Program.prototype.csr =
- Program.prototype.setScrollRegion = function(top, bottom) {
- if (!this.zero) {
- top = (top || 1) - 1;
- bottom = (bottom || this.rows) - 1;
- } else {
- top = top || 0;
- bottom = bottom || (this.rows - 1);
- }
- this.scrollTop = top;
- this.scrollBottom = bottom;
- this.x = 0;
- this.y = 0;
- this._ncoords();
- if (this.tput) return this.put.csr(top, bottom);
- return this._write('\x1b[' + (top + 1) + ';' + (bottom + 1) + 'r');
- };
- // CSI s
- // Save cursor (ANSI.SYS).
- Program.prototype.scA =
- Program.prototype.saveCursorA = function() {
- this.savedX = this.x;
- this.savedY = this.y;
- if (this.tput) return this.put.sc();
- return this._write('\x1b[s');
- };
- // CSI u
- // Restore cursor (ANSI.SYS).
- Program.prototype.rcA =
- Program.prototype.restoreCursorA = function() {
- this.x = this.savedX || 0;
- this.y = this.savedY || 0;
- if (this.tput) return this.put.rc();
- return this._write('\x1b[u');
- };
- /**
- * Lesser Used
- */
- // CSI Ps I
- // Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
- Program.prototype.cht =
- Program.prototype.cursorForwardTab = function(param) {
- this.x += 8;
- this._ncoords();
- if (this.tput) return this.put.tab(param);
- return this._write('\x1b[' + (param || 1) + 'I');
- };
- // CSI Ps S Scroll up Ps lines (default = 1) (SU).
- Program.prototype.su =
- Program.prototype.scrollUp = function(param) {
- this.y -= param || 1;
- this._ncoords();
- if (this.tput) return this.put.parm_index(param);
- return this._write('\x1b[' + (param || 1) + 'S');
- };
- // CSI Ps T Scroll down Ps lines (default = 1) (SD).
- Program.prototype.sd =
- Program.prototype.scrollDown = function(param) {
- this.y += param || 1;
- this._ncoords();
- if (this.tput) return this.put.parm_rindex(param);
- return this._write('\x1b[' + (param || 1) + 'T');
- };
- // CSI Ps ; Ps ; Ps ; Ps ; Ps T
- // Initiate highlight mouse tracking. Parameters are
- // [func;startx;starty;firstrow;lastrow]. See the section Mouse
- // Tracking.
- Program.prototype.initMouseTracking = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + 'T');
- };
- // CSI > Ps; Ps T
- // Reset one or more features of the title modes to the default
- // value. Normally, "reset" disables the feature. It is possi-
- // ble to disable the ability to reset features by compiling a
- // different default for the title modes into xterm.
- // Ps = 0 -> Do not set window/icon labels using hexadecimal.
- // Ps = 1 -> Do not query window/icon labels using hexadeci-
- // mal.
- // Ps = 2 -> Do not set window/icon labels using UTF-8.
- // Ps = 3 -> Do not query window/icon labels using UTF-8.
- // (See discussion of "Title Modes").
- Program.prototype.resetTitleModes = function() {
- return this._write('\x1b[>' + slice.call(arguments).join(';') + 'T');
- };
- // CSI Ps Z Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
- Program.prototype.cbt =
- Program.prototype.cursorBackwardTab = function(param) {
- this.x -= 8;
- this._ncoords();
- if (this.tput) return this.put.cbt(param);
- return this._write('\x1b[' + (param || 1) + 'Z');
- };
- // CSI Ps b Repeat the preceding graphic character Ps times (REP).
- Program.prototype.rep =
- Program.prototype.repeatPrecedingCharacter = function(param) {
- this.x += param || 1;
- this._ncoords();
- if (this.tput) return this.put.rep(param);
- return this._write('\x1b[' + (param || 1) + 'b');
- };
- // CSI Ps g Tab Clear (TBC).
- // Ps = 0 -> Clear Current Column (default).
- // Ps = 3 -> Clear All.
- // Potentially:
- // Ps = 2 -> Clear Stops on Line.
- // http://vt100.net/annarbor/aaa-ug/section6.html
- Program.prototype.tbc =
- Program.prototype.tabClear = function(param) {
- if (this.tput) return this.put.tbc(param);
- return this._write('\x1b[' + (param || 0) + 'g');
- };
- // CSI Pm i Media Copy (MC).
- // Ps = 0 -> Print screen (default).
- // Ps = 4 -> Turn off printer controller mode.
- // Ps = 5 -> Turn on printer controller mode.
- // CSI ? Pm i
- // Media Copy (MC, DEC-specific).
- // Ps = 1 -> Print line containing cursor.
- // Ps = 4 -> Turn off autoprint mode.
- // Ps = 5 -> Turn on autoprint mode.
- // Ps = 1 0 -> Print composed display, ignores DECPEX.
- // Ps = 1 1 -> Print all pages.
- Program.prototype.mc =
- Program.prototype.mediaCopy = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + 'i');
- };
- Program.prototype.print_screen =
- Program.prototype.ps =
- Program.prototype.mc0 = function() {
- if (this.tput) return this.put.mc0();
- return this.mc('0');
- };
- Program.prototype.prtr_on =
- Program.prototype.po =
- Program.prototype.mc5 = function() {
- if (this.tput) return this.put.mc5();
- return this.mc('5');
- };
- Program.prototype.prtr_off =
- Program.prototype.pf =
- Program.prototype.mc4 = function() {
- if (this.tput) return this.put.mc4();
- return this.mc('4');
- };
- Program.prototype.prtr_non =
- Program.prototype.pO =
- Program.prototype.mc5p = function() {
- if (this.tput) return this.put.mc5p();
- return this.mc('?5');
- };
- // CSI > Ps; Ps m
- // Set or reset resource-values used by xterm to decide whether
- // to construct escape sequences holding information about the
- // modifiers pressed with a given key. The first parameter iden-
- // tifies the resource to set/reset. The second parameter is the
- // value to assign to the resource. If the second parameter is
- // omitted, the resource is reset to its initial value.
- // Ps = 1 -> modifyCursorKeys.
- // Ps = 2 -> modifyFunctionKeys.
- // Ps = 4 -> modifyOtherKeys.
- // If no parameters are given, all resources are reset to their
- // initial values.
- Program.prototype.setResources = function() {
- return this._write('\x1b[>' + slice.call(arguments).join(';') + 'm');
- };
- // CSI > Ps n
- // Disable modifiers which may be enabled via the CSI > Ps; Ps m
- // sequence. This corresponds to a resource value of "-1", which
- // cannot be set with the other sequence. The parameter identi-
- // fies the resource to be disabled:
- // Ps = 1 -> modifyCursorKeys.
- // Ps = 2 -> modifyFunctionKeys.
- // Ps = 4 -> modifyOtherKeys.
- // If the parameter is omitted, modifyFunctionKeys is disabled.
- // When modifyFunctionKeys is disabled, xterm uses the modifier
- // keys to make an extended sequence of functions rather than
- // adding a parameter to each function key to denote the modi-
- // fiers.
- Program.prototype.disableModifiers = function(param) {
- return this._write('\x1b[>' + (param || '') + 'n');
- };
- // CSI > Ps p
- // Set resource value pointerMode. This is used by xterm to
- // decide whether to hide the pointer cursor as the user types.
- // Valid values for the parameter:
- // Ps = 0 -> never hide the pointer.
- // Ps = 1 -> hide if the mouse tracking mode is not enabled.
- // Ps = 2 -> always hide the pointer. If no parameter is
- // given, xterm uses the default, which is 1 .
- Program.prototype.setPointerMode = function(param) {
- return this._write('\x1b[>' + (param || '') + 'p');
- };
- // CSI ! p Soft terminal reset (DECSTR).
- // http://vt100.net/docs/vt220-rm/table4-10.html
- Program.prototype.decstr =
- Program.prototype.rs2 =
- Program.prototype.softReset = function() {
- //if (this.tput) return this.put.init_2string();
- //if (this.tput) return this.put.reset_2string();
- if (this.tput) return this.put.rs2();
- //return this._write('\x1b[!p');
- //return this._write('\x1b[!p\x1b[?3;4l\x1b[4l\x1b>'); // init
- return this._write('\x1b[!p\x1b[?3;4l\x1b[4l\x1b>'); // reset
- };
- // CSI Ps$ p
- // Request ANSI mode (DECRQM). For VT300 and up, reply is
- // CSI Ps; Pm$ y
- // where Ps is the mode number as in RM, and Pm is the mode
- // value:
- // 0 - not recognized
- // 1 - set
- // 2 - reset
- // 3 - permanently set
- // 4 - permanently reset
- Program.prototype.decrqm =
- Program.prototype.requestAnsiMode = function(param) {
- return this._write('\x1b[' + (param || '') + '$p');
- };
- // CSI ? Ps$ p
- // Request DEC private mode (DECRQM). For VT300 and up, reply is
- // CSI ? Ps; Pm$ p
- // where Ps is the mode number as in DECSET, Pm is the mode value
- // as in the ANSI DECRQM.
- Program.prototype.decrqmp =
- Program.prototype.requestPrivateMode = function(param) {
- return this._write('\x1b[?' + (param || '') + '$p');
- };
- // CSI Ps ; Ps " p
- // Set conformance level (DECSCL). Valid values for the first
- // parameter:
- // Ps = 6 1 -> VT100.
- // Ps = 6 2 -> VT200.
- // Ps = 6 3 -> VT300.
- // Valid values for the second parameter:
- // Ps = 0 -> 8-bit controls.
- // Ps = 1 -> 7-bit controls (always set for VT100).
- // Ps = 2 -> 8-bit controls.
- Program.prototype.decscl =
- Program.prototype.setConformanceLevel = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + '"p');
- };
- // CSI Ps q Load LEDs (DECLL).
- // Ps = 0 -> Clear all LEDS (default).
- // Ps = 1 -> Light Num Lock.
- // Ps = 2 -> Light Caps Lock.
- // Ps = 3 -> Light Scroll Lock.
- // Ps = 2 1 -> Extinguish Num Lock.
- // Ps = 2 2 -> Extinguish Caps Lock.
- // Ps = 2 3 -> Extinguish Scroll Lock.
- Program.prototype.decll =
- Program.prototype.loadLEDs = function(param) {
- return this._write('\x1b[' + (param || '') + 'q');
- };
- // CSI Ps SP q
- // Set cursor style (DECSCUSR, VT520).
- // Ps = 0 -> blinking block.
- // Ps = 1 -> blinking block (default).
- // Ps = 2 -> steady block.
- // Ps = 3 -> blinking underline.
- // Ps = 4 -> steady underline.
- Program.prototype.decscusr =
- Program.prototype.setCursorStyle = function(param) {
- switch (param) {
- case 'blinking block':
- param = 1;
- break;
- case 'block':
- case 'steady block':
- param = 2;
- break;
- case 'blinking underline':
- param = 3;
- break;
- case 'underline':
- case 'steady underline':
- param = 4;
- break;
- case 'blinking bar':
- param = 5;
- break;
- case 'bar':
- case 'steady bar':
- param = 6;
- break;
- }
- if (param === 2 && this.has('Se')) {
- return this.put.Se();
- }
- if (this.has('Ss')) {
- return this.put.Ss(param);
- }
- return this._write('\x1b[' + (param || 1) + ' q');
- };
- // CSI Ps " q
- // Select character protection attribute (DECSCA). Valid values
- // for the parameter:
- // Ps = 0 -> DECSED and DECSEL can erase (default).
- // Ps = 1 -> DECSED and DECSEL cannot erase.
- // Ps = 2 -> DECSED and DECSEL can erase.
- Program.prototype.decsca =
- Program.prototype.setCharProtectionAttr = function(param) {
- return this._write('\x1b[' + (param || 0) + '"q');
- };
- // CSI ? Pm r
- // Restore DEC Private Mode Values. The value of Ps previously
- // saved is restored. Ps values are the same as for DECSET.
- Program.prototype.restorePrivateValues = function() {
- return this._write('\x1b[?' + slice.call(arguments).join(';') + 'r');
- };
- // CSI Pt; Pl; Pb; Pr; Ps$ r
- // Change Attributes in Rectangular Area (DECCARA), VT400 and up.
- // Pt; Pl; Pb; Pr denotes the rectangle.
- // Ps denotes the SGR attributes to change: 0, 1, 4, 5, 7.
- // NOTE: xterm doesn't enable this code by default.
- Program.prototype.deccara =
- Program.prototype.setAttrInRectangle = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + '$r');
- };
- // CSI ? Pm s
- // Save DEC Private Mode Values. Ps values are the same as for
- // DECSET.
- Program.prototype.savePrivateValues = function() {
- return this._write('\x1b[?' + slice.call(arguments).join(';') + 's');
- };
- // CSI Ps ; Ps ; Ps t
- // Window manipulation (from dtterm, as well as extensions).
- // These controls may be disabled using the allowWindowOps
- // resource. Valid values for the first (and any additional
- // parameters) are:
- // Ps = 1 -> De-iconify window.
- // Ps = 2 -> Iconify window.
- // Ps = 3 ; x ; y -> Move window to [x, y].
- // Ps = 4 ; height ; width -> Resize the xterm window to
- // height and width in pixels.
- // Ps = 5 -> Raise the xterm window to the front of the stack-
- // ing order.
- // Ps = 6 -> Lower the xterm window to the bottom of the
- // stacking order.
- // Ps = 7 -> Refresh the xterm window.
- // Ps = 8 ; height ; width -> Resize the text area to
- // [height;width] in characters.
- // Ps = 9 ; 0 -> Restore maximized window.
- // Ps = 9 ; 1 -> Maximize window (i.e., resize to screen
- // size).
- // Ps = 1 0 ; 0 -> Undo full-screen mode.
- // Ps = 1 0 ; 1 -> Change to full-screen.
- // Ps = 1 1 -> Report xterm window state. If the xterm window
- // is open (non-iconified), it returns CSI 1 t . If the xterm
- // window is iconified, it returns CSI 2 t .
- // Ps = 1 3 -> Report xterm window position. Result is CSI 3
- // ; x ; y t
- // Ps = 1 4 -> Report xterm window in pixels. Result is CSI
- // 4 ; height ; width t
- // Ps = 1 8 -> Report the size of the text area in characters.
- // Result is CSI 8 ; height ; width t
- // Ps = 1 9 -> Report the size of the screen in characters.
- // Result is CSI 9 ; height ; width t
- // Ps = 2 0 -> Report xterm window's icon label. Result is
- // OSC L label ST
- // Ps = 2 1 -> Report xterm window's title. Result is OSC l
- // label ST
- // Ps = 2 2 ; 0 -> Save xterm icon and window title on
- // stack.
- // Ps = 2 2 ; 1 -> Save xterm icon title on stack.
- // Ps = 2 2 ; 2 -> Save xterm window title on stack.
- // Ps = 2 3 ; 0 -> Restore xterm icon and window title from
- // stack.
- // Ps = 2 3 ; 1 -> Restore xterm icon title from stack.
- // Ps = 2 3 ; 2 -> Restore xterm window title from stack.
- // Ps >= 2 4 -> Resize to Ps lines (DECSLPP).
- Program.prototype.manipulateWindow = function() {
- var args = slice.call(arguments);
- var callback = typeof args[args.length - 1] === 'function'
- ? args.pop()
- : function() {};
- return this.response('window-manipulation',
- '\x1b[' + args.join(';') + 't', callback);
- };
- Program.prototype.getWindowSize = function(callback) {
- return this.manipulateWindow(18, callback);
- };
- // CSI Pt; Pl; Pb; Pr; Ps$ t
- // Reverse Attributes in Rectangular Area (DECRARA), VT400 and
- // up.
- // Pt; Pl; Pb; Pr denotes the rectangle.
- // Ps denotes the attributes to reverse, i.e., 1, 4, 5, 7.
- // NOTE: xterm doesn't enable this code by default.
- Program.prototype.decrara =
- Program.prototype.reverseAttrInRectangle = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + '$t');
- };
- // CSI > Ps; Ps t
- // Set one or more features of the title modes. Each parameter
- // enables a single feature.
- // Ps = 0 -> Set window/icon labels using hexadecimal.
- // Ps = 1 -> Query window/icon labels using hexadecimal.
- // Ps = 2 -> Set window/icon labels using UTF-8.
- // Ps = 3 -> Query window/icon labels using UTF-8. (See dis-
- // cussion of "Title Modes")
- // XXX VTE bizarelly echos this:
- Program.prototype.setTitleModeFeature = function() {
- return this._twrite('\x1b[>' + slice.call(arguments).join(';') + 't');
- };
- // CSI Ps SP t
- // Set warning-bell volume (DECSWBV, VT520).
- // Ps = 0 or 1 -> off.
- // Ps = 2 , 3 or 4 -> low.
- // Ps = 5 , 6 , 7 , or 8 -> high.
- Program.prototype.decswbv =
- Program.prototype.setWarningBellVolume = function(param) {
- return this._write('\x1b[' + (param || '') + ' t');
- };
- // CSI Ps SP u
- // Set margin-bell volume (DECSMBV, VT520).
- // Ps = 1 -> off.
- // Ps = 2 , 3 or 4 -> low.
- // Ps = 0 , 5 , 6 , 7 , or 8 -> high.
- Program.prototype.decsmbv =
- Program.prototype.setMarginBellVolume = function(param) {
- return this._write('\x1b[' + (param || '') + ' u');
- };
- // CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
- // Copy Rectangular Area (DECCRA, VT400 and up).
- // Pt; Pl; Pb; Pr denotes the rectangle.
- // Pp denotes the source page.
- // Pt; Pl denotes the target location.
- // Pp denotes the target page.
- // NOTE: xterm doesn't enable this code by default.
- Program.prototype.deccra =
- Program.prototype.copyRectangle = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + '$v');
- };
- // CSI Pt ; Pl ; Pb ; Pr ' w
- // Enable Filter Rectangle (DECEFR), VT420 and up.
- // Parameters are [top;left;bottom;right].
- // Defines the coordinates of a filter rectangle and activates
- // it. Anytime the locator is detected outside of the filter
- // rectangle, an outside rectangle event is generated and the
- // rectangle is disabled. Filter rectangles are always treated
- // as "one-shot" events. Any parameters that are omitted default
- // to the current locator position. If all parameters are omit-
- // ted, any locator motion will be reported. DECELR always can-
- // cels any prevous rectangle definition.
- Program.prototype.decefr =
- Program.prototype.enableFilterRectangle = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + '\'w');
- };
- // CSI Ps x Request Terminal Parameters (DECREQTPARM).
- // if Ps is a "0" (default) or "1", and xterm is emulating VT100,
- // the control sequence elicits a response of the same form whose
- // parameters describe the terminal:
- // Ps -> the given Ps incremented by 2.
- // Pn = 1 <- no parity.
- // Pn = 1 <- eight bits.
- // Pn = 1 <- 2 8 transmit 38.4k baud.
- // Pn = 1 <- 2 8 receive 38.4k baud.
- // Pn = 1 <- clock multiplier.
- // Pn = 0 <- STP flags.
- Program.prototype.decreqtparm =
- Program.prototype.requestParameters = function(param) {
- return this._write('\x1b[' + (param || 0) + 'x');
- };
- // CSI Ps x Select Attribute Change Extent (DECSACE).
- // Ps = 0 -> from start to end position, wrapped.
- // Ps = 1 -> from start to end position, wrapped.
- // Ps = 2 -> rectangle (exact).
- Program.prototype.decsace =
- Program.prototype.selectChangeExtent = function(param) {
- return this._write('\x1b[' + (param || 0) + 'x');
- };
- // CSI Pc; Pt; Pl; Pb; Pr$ x
- // Fill Rectangular Area (DECFRA), VT420 and up.
- // Pc is the character to use.
- // Pt; Pl; Pb; Pr denotes the rectangle.
- // NOTE: xterm doesn't enable this code by default.
- Program.prototype.decfra =
- Program.prototype.fillRectangle = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + '$x');
- };
- // CSI Ps ; Pu ' z
- // Enable Locator Reporting (DECELR).
- // Valid values for the first parameter:
- // Ps = 0 -> Locator disabled (default).
- // Ps = 1 -> Locator enabled.
- // Ps = 2 -> Locator enabled for one report, then disabled.
- // The second parameter specifies the coordinate unit for locator
- // reports.
- // Valid values for the second parameter:
- // Pu = 0 <- or omitted -> default to character cells.
- // Pu = 1 <- device physical pixels.
- // Pu = 2 <- character cells.
- Program.prototype.decelr =
- Program.prototype.enableLocatorReporting = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + '\'z');
- };
- // CSI Pt; Pl; Pb; Pr$ z
- // Erase Rectangular Area (DECERA), VT400 and up.
- // Pt; Pl; Pb; Pr denotes the rectangle.
- // NOTE: xterm doesn't enable this code by default.
- Program.prototype.decera =
- Program.prototype.eraseRectangle = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + '$z');
- };
- // CSI Pm ' {
- // Select Locator Events (DECSLE).
- // Valid values for the first (and any additional parameters)
- // are:
- // Ps = 0 -> only respond to explicit host requests (DECRQLP).
- // (This is default). It also cancels any filter
- // rectangle.
- // Ps = 1 -> report button down transitions.
- // Ps = 2 -> do not report button down transitions.
- // Ps = 3 -> report button up transitions.
- // Ps = 4 -> do not report button up transitions.
- Program.prototype.decsle =
- Program.prototype.setLocatorEvents = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + '\'{');
- };
- // CSI Pt; Pl; Pb; Pr$ {
- // Selective Erase Rectangular Area (DECSERA), VT400 and up.
- // Pt; Pl; Pb; Pr denotes the rectangle.
- Program.prototype.decsera =
- Program.prototype.selectiveEraseRectangle = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + '${');
- };
- // CSI Ps ' |
- // Request Locator Position (DECRQLP).
- // Valid values for the parameter are:
- // Ps = 0 , 1 or omitted -> transmit a single DECLRP locator
- // report.
- // If Locator Reporting has been enabled by a DECELR, xterm will
- // respond with a DECLRP Locator Report. This report is also
- // generated on button up and down events if they have been
- // enabled with a DECSLE, or when the locator is detected outside
- // of a filter rectangle, if filter rectangles have been enabled
- // with a DECEFR.
- // -> CSI Pe ; Pb ; Pr ; Pc ; Pp & w
- // Parameters are [event;button;row;column;page].
- // Valid values for the event:
- // Pe = 0 -> locator unavailable - no other parameters sent.
- // Pe = 1 -> request - xterm received a DECRQLP.
- // Pe = 2 -> left button down.
- // Pe = 3 -> left button up.
- // Pe = 4 -> middle button down.
- // Pe = 5 -> middle button up.
- // Pe = 6 -> right button down.
- // Pe = 7 -> right button up.
- // Pe = 8 -> M4 button down.
- // Pe = 9 -> M4 button up.
- // Pe = 1 0 -> locator outside filter rectangle.
- // ``button'' parameter is a bitmask indicating which buttons are
- // pressed:
- // Pb = 0 <- no buttons down.
- // Pb & 1 <- right button down.
- // Pb & 2 <- middle button down.
- // Pb & 4 <- left button down.
- // Pb & 8 <- M4 button down.
- // ``row'' and ``column'' parameters are the coordinates of the
- // locator position in the xterm window, encoded as ASCII deci-
- // mal.
- // The ``page'' parameter is not used by xterm, and will be omit-
- // ted.
- Program.prototype.decrqlp =
- Program.prototype.req_mouse_pos =
- Program.prototype.reqmp =
- Program.prototype.requestLocatorPosition = function(param, callback) {
- // See also:
- // get_mouse / getm / Gm
- // mouse_info / minfo / Mi
- // Correct for tput?
- if (this.has('req_mouse_pos')) {
- var code = this.tput.req_mouse_pos(param);
- return this.response('locator-position', code, callback);
- }
- return this.response('locator-position',
- '\x1b[' + (param || '') + '\'|', callback);
- };
- // CSI P m SP }
- // Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
- // NOTE: xterm doesn't enable this code by default.
- Program.prototype.decic =
- Program.prototype.insertColumns = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + ' }');
- };
- // CSI P m SP ~
- // Delete P s Column(s) (default = 1) (DECDC), VT420 and up
- // NOTE: xterm doesn't enable this code by default.
- Program.prototype.decdc =
- Program.prototype.deleteColumns = function() {
- return this._write('\x1b[' + slice.call(arguments).join(';') + ' ~');
- };
- Program.prototype.out = function(name) {
- var args = Array.prototype.slice.call(arguments, 1);
- this.ret = true;
- var out = this[name].apply(this, args);
- this.ret = false;
- return out;
- };
- Program.prototype.sigtstp = function(callback) {
- var resume = this.pause();
- process.once('SIGCONT', function() {
- resume();
- if (callback) callback();
- });
- process.kill(process.pid, 'SIGTSTP');
- };
- Program.prototype.pause = function(callback) {
- var self = this
- , isAlt = this.isAlt
- , mouseEnabled = this.mouseEnabled;
- this.lsaveCursor('pause');
- //this.csr(0, screen.height - 1);
- if (isAlt) this.normalBuffer();
- this.showCursor();
- if (mouseEnabled) this.disableMouse();
- var write = this.output.write;
- this.output.write = function() {};
- if (this.input.setRawMode) {
- this.input.setRawMode(false);
- }
- this.input.pause();
- return this._resume = function() {
- delete self._resume;
- if (self.input.setRawMode) {
- self.input.setRawMode(true);
- }
- self.input.resume();
- self.output.write = write;
- if (isAlt) self.alternateBuffer();
- //self.csr(0, screen.height - 1);
- if (mouseEnabled) self.enableMouse();
- self.lrestoreCursor('pause', true);
- if (callback) callback();
- };
- };
- Program.prototype.resume = function() {
- if (this._resume) return this._resume();
- };
- /**
- * Helpers
- */
- // We could do this easier by just manipulating the _events object, or for
- // older versions of node, manipulating the array returned by listeners(), but
- // neither of these methods are guaranteed to work in future versions of node.
- function unshiftEvent(obj, event, listener) {
- var listeners = obj.listeners(event);
- obj.removeAllListeners(event);
- obj.on(event, listener);
- listeners.forEach(function(listener) {
- obj.on(event, listener);
- });
- }
- function merge(out) {
- slice.call(arguments, 1).forEach(function(obj) {
- Object.keys(obj).forEach(function(key) {
- out[key] = obj[key];
- });
- });
- return out;
- }
- /**
- * Expose
- */
- module.exports = Program;
|