PageRenderTime 63ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/program.js

https://github.com/prodigeni/blessed
JavaScript | 3581 lines | 2447 code | 375 blank | 759 comment | 459 complexity | 9cf7620da05e61e38f7a2e292cb14e27 MD5 | raw file
  1. /**
  2. * program.js - basic curses-like functionality for blessed.
  3. * Copyright (c) 2013, Christopher Jeffrey (MIT License).
  4. * https://github.com/chjj/blessed
  5. */
  6. /**
  7. * Modules
  8. */
  9. var EventEmitter = require('events').EventEmitter
  10. , StringDecoder = require('string_decoder').StringDecoder
  11. , util = require('util')
  12. , fs = require('fs');
  13. var Tput = require('./tput')
  14. , colors = require('./colors')
  15. , slice = Array.prototype.slice;
  16. /**
  17. * Program
  18. */
  19. function Program(options) {
  20. var self = this;
  21. if (!(this instanceof Program)) {
  22. return new Program(options);
  23. }
  24. EventEmitter.call(this);
  25. if (!options || options.__proto__ !== Object.prototype) {
  26. options = {
  27. input: arguments[0],
  28. output: arguments[1]
  29. };
  30. }
  31. this.options = options;
  32. this.input = options.input || process.stdin;
  33. this.output = options.output || process.stdout;
  34. options.log = options.log || options.dump;
  35. if (options.log) {
  36. this._logger = fs.createWriteStream(options.log);
  37. if (options.dump) this.setupDump();
  38. }
  39. this.zero = options.zero !== false;
  40. this.useBuffer = options.buffer;
  41. this.x = 0;
  42. this.y = 0;
  43. this.savedX = 0;
  44. this.savedY = 0;
  45. this.cols = this.output.columns || 1;
  46. this.rows = this.output.rows || 1;
  47. this.scrollTop = 0;
  48. this.scrollBottom = this.rows - 1;
  49. this.terminal = options.term
  50. || options.terminal
  51. || process.env.TERM
  52. || (process.platform === 'win32' ? 'windows-ansi' : 'xterm');
  53. this._buf = '';
  54. this._flush = this.flush.bind(this);
  55. unshiftEvent(process, 'exit', function() {
  56. // Ensure the buffer is flushed (it should
  57. // always be at this point, but who knows).
  58. self.flush();
  59. // Ensure _exiting is set (could technically
  60. // use process._exiting).
  61. self._exiting = true;
  62. });
  63. if (!Program.global) {
  64. Program.global = this;
  65. }
  66. if (options.tput !== false) {
  67. this.setupTput();
  68. }
  69. this.listen();
  70. }
  71. Program.prototype.__proto__ = EventEmitter.prototype;
  72. Program.prototype.log = function() {
  73. return this._log('LOG', util.format.apply(util, arguments));
  74. };
  75. Program.prototype.debug = function() {
  76. if (!this.options.debug) return;
  77. return this._log('DEBUG', util.format.apply(util, arguments));
  78. };
  79. Program.prototype._log = function(pre, msg) {
  80. if (!this._logger) return;
  81. return this._logger.write(pre + ': ' + msg + '\n-\n');
  82. };
  83. Program.prototype.setupDump = function() {
  84. var self = this
  85. , write = this.output.write
  86. , decoder = new StringDecoder('utf8');
  87. function stringify(data) {
  88. return caret(data
  89. .replace(/\r/g, '\\r')
  90. .replace(/\n/g, '\\n')
  91. .replace(/\t/g, '\\t'))
  92. .replace(/[^ -~]/g, function(ch) {
  93. if (ch.charCodeAt(0) > 0xff) return ch;
  94. ch = ch.charCodeAt(0).toString(16);
  95. if (ch.length > 2) {
  96. if (ch.length < 4) ch = '0' + ch;
  97. return '\\u' + ch;
  98. }
  99. if (ch.length < 2) ch = '0' + ch;
  100. return '\\x' + ch;
  101. });
  102. }
  103. function caret(data) {
  104. return data.replace(/[\0\x80\x1b-\x1f\x7f\x01-\x1a]/g, function(ch) {
  105. switch (ch) {
  106. case '\0':
  107. case '\200':
  108. ch = '@';
  109. break;
  110. case '\x1b':
  111. ch = '[';
  112. break;
  113. case '\x1c':
  114. ch = '\\';
  115. break;
  116. case '\x1d':
  117. ch = ']';
  118. break;
  119. case '\x1e':
  120. ch = '^';
  121. break;
  122. case '\x1f':
  123. ch = '_';
  124. break;
  125. case '\x7f':
  126. ch = '?';
  127. break;
  128. default:
  129. ch = ch.charCodeAt(0);
  130. // From ('A' - 64) to ('Z' - 64).
  131. if (ch >= 1 && ch <= 26) {
  132. ch = String.fromCharCode(ch + 64);
  133. } else {
  134. return String.fromCharCode(ch);
  135. }
  136. break;
  137. }
  138. return '^' + ch;
  139. });
  140. }
  141. this.input.on('data', function(data) {
  142. self._log('IN', stringify(decoder.write(data)));
  143. });
  144. this.output.write = function(data) {
  145. self._log('OUT', stringify(data));
  146. return write.apply(this, arguments);
  147. };
  148. };
  149. Program.prototype.setupTput = function() {
  150. if (this._tputSetup) return;
  151. this._tputSetup = true;
  152. var self = this
  153. , options = this.options
  154. , write = this.write.bind(this);
  155. var tput = this.tput = new Tput({
  156. term: this.terminal,
  157. padding: options.padding,
  158. extended: options.extended,
  159. printf: options.printf,
  160. termcap: options.termcap
  161. });
  162. this.put = function() {
  163. var args = slice.call(arguments)
  164. , cap = args.shift();
  165. if (tput[cap]) {
  166. return this._write(tput[cap].apply(tput, args));
  167. }
  168. };
  169. Object.keys(tput).forEach(function(key) {
  170. if (self[key] == null) {
  171. self[key] = tput[key];
  172. }
  173. if (typeof tput[key] !== 'function') {
  174. self.put[key] = tput[key];
  175. return;
  176. }
  177. if (options.padding) {
  178. self.put[key] = function() {
  179. return tput._print(tput[key].apply(tput, arguments), write);
  180. };
  181. } else {
  182. self.put[key] = function() {
  183. return self._write(tput[key].apply(tput, arguments));
  184. };
  185. }
  186. });
  187. };
  188. Program.prototype.has = function(name) {
  189. return this.tput
  190. ? this.tput.has(name)
  191. : false;
  192. };
  193. Program.prototype.term = function(is) {
  194. return this.terminal.indexOf(is) === 0;
  195. };
  196. Program.prototype.listen = function() {
  197. var readline = require('readline')
  198. , self = this;
  199. if (!this.input.isTTY || !this.output.isTTY) {
  200. throw new Error('Not a terminal.');
  201. }
  202. // Input
  203. this.input.on('keypress', function(ch, key) {
  204. key = key || { ch: ch };
  205. if (key.name === 'undefined'
  206. && (key.code === '[M' || key.code === '[I' || key.code === '[O')) {
  207. // A mouse sequence. The readline module doesn't understand these.
  208. return;
  209. }
  210. if (key.name === 'undefined') {
  211. // Not sure what this is, but we should probably ignore it.
  212. return;
  213. }
  214. if (key.name === 'enter' && key.sequence === '\n') {
  215. key.name = 'linefeed';
  216. }
  217. if (key.name === 'return' && key.sequence === '\r') {
  218. self.input.emit('keypress', ch, merge({}, key, { name: 'enter' }));
  219. }
  220. var name = (key.ctrl ? 'C-' : '')
  221. + (key.meta ? 'M-' : '')
  222. + (key.shift && key.name ? 'S-' : '')
  223. + (key.name || ch);
  224. key.full = name;
  225. self.emit('keypress', ch, key);
  226. self.emit('key ' + name, ch, key);
  227. });
  228. this.input.on('data', function(data) {
  229. self.emit('data', data);
  230. });
  231. readline.emitKeypressEvents(this.input);
  232. this.on('newListener', function fn(type) {
  233. if (type === 'keypress' || type === 'mouse') {
  234. self.removeListener('newListener', fn);
  235. if (!self.input.isRaw) {
  236. self.input.setRawMode(true);
  237. self.input.resume();
  238. }
  239. }
  240. });
  241. this.on('newListener', function fn(type) {
  242. if (type === 'mouse') {
  243. self.removeListener('newListener', fn);
  244. self.bindMouse();
  245. }
  246. });
  247. // Output
  248. this.output.on('resize', function() {
  249. self.cols = self.output.columns;
  250. self.rows = self.output.rows;
  251. self.emit('resize');
  252. });
  253. };
  254. Program.prototype.key = function(key, listener) {
  255. if (typeof key === 'string') key = key.split(/\s*,\s*/);
  256. key.forEach(function(key) {
  257. return this.on('key ' + key, listener);
  258. }, this);
  259. };
  260. Program.prototype.onceKey = function(key, listener) {
  261. if (typeof key === 'string') key = key.split(/\s*,\s*/);
  262. key.forEach(function(key) {
  263. return this.once('key ' + key, listener);
  264. }, this);
  265. };
  266. Program.prototype.unkey =
  267. Program.prototype.removeKey = function(key, listener) {
  268. if (typeof key === 'string') key = key.split(/\s*,\s*/);
  269. key.forEach(function(key) {
  270. return this.removeListener('key ' + key, listener);
  271. }, this);
  272. };
  273. // XTerm mouse events
  274. // http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
  275. // To better understand these
  276. // the xterm code is very helpful:
  277. // Relevant files:
  278. // button.c, charproc.c, misc.c
  279. // Relevant functions in xterm/button.c:
  280. // BtnCode, EmitButtonCode, EditorButton, SendMousePosition
  281. // send a mouse event:
  282. // regular/utf8: ^[[M Cb Cx Cy
  283. // urxvt: ^[[ Cb ; Cx ; Cy M
  284. // sgr: ^[[ Cb ; Cx ; Cy M/m
  285. // vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r
  286. // locator: CSI P e ; P b ; P r ; P c ; P p & w
  287. // motion example of a left click:
  288. // ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
  289. // mouseup, mousedown, mousewheel
  290. // left click: ^[[M 3<^[[M#3<
  291. // mousewheel up: ^[[M`3>
  292. Program.prototype.bindMouse = function() {
  293. if (this._boundMouse) return;
  294. this._boundMouse = true;
  295. var decoder = new StringDecoder('utf8')
  296. , self = this;
  297. this.on('data', function(data) {
  298. data = decoder.write(data);
  299. if (!data) return;
  300. self._bindMouse(data);
  301. });
  302. };
  303. Program.prototype._bindMouse = function(s) {
  304. var self = this
  305. , key
  306. , parts;
  307. key = {
  308. name: undefined,
  309. ctrl: false,
  310. meta: false,
  311. shift: false
  312. };
  313. if (Buffer.isBuffer(s)) {
  314. if (s[0] > 127 && s[1] === undefined) {
  315. s[0] -= 128;
  316. s = '\x1b' + s.toString('utf-8');
  317. } else {
  318. s = s.toString('utf-8');
  319. }
  320. }
  321. // XTerm / X10
  322. if (parts = /^\x1b\[M([\x00\u0020-\uffff]{3})/.exec(s)) {
  323. var b = parts[1].charCodeAt(0)
  324. , x = parts[1].charCodeAt(1)
  325. , y = parts[1].charCodeAt(2)
  326. , mod;
  327. key.name = 'mouse';
  328. key.type = 'X10';
  329. key.raw = [b, x, y, parts[0]];
  330. key.x = x - 32;
  331. key.y = y - 32;
  332. if (key.x === -32) key.x = 255;
  333. if (key.y === -32) key.y = 255;
  334. if (this.zero) key.x--, key.y--;
  335. mod = b >> 2;
  336. key.shift = !!(mod & 1);
  337. key.meta = !!((mod >> 1) & 1);
  338. key.ctrl = !!((mod >> 2) & 1);
  339. b -= 32;
  340. if ((b >> 6) & 1) {
  341. key.action = b & 1 ? 'wheeldown' : 'wheelup';
  342. key.button = 'middle';
  343. } else if (b === 3) {
  344. // Could also be a movement.
  345. key.action = 'mouseup';
  346. key.button = 'unknown';
  347. } else {
  348. key.action = 'mousedown';
  349. key.button =
  350. b === 0 ? 'left'
  351. : b === 1 ? 'middle'
  352. : b === 2 ? 'right'
  353. : 'unknown';
  354. }
  355. // It's a movement
  356. // Wrong
  357. //if (b > 32 && b < 64) {
  358. // delete key.button;
  359. // key.action = 'mousemove';
  360. //}
  361. // Probably a movement.
  362. if (key.action === 'mousedown' && key.button === 'unknown') {
  363. delete key.button;
  364. key.action = 'mousemove';
  365. }
  366. self.emit('keypress', null, key);
  367. self.emit('mouse', key);
  368. return;
  369. }
  370. // URxvt
  371. if (parts = /^\x1b\[(\d+;\d+;\d+)M/.exec(s)) {
  372. var parts = parts[1].split(';')
  373. , b = +parts[0]
  374. , x = +parts[1]
  375. , y = +parts[2];
  376. key.name = 'mouse';
  377. key.type = 'urxvt';
  378. key.x = x;
  379. key.y = y;
  380. if (this.zero) key.x--, key.y--;
  381. // NOTE: Duplicate of the above.
  382. mod = b >> 3;
  383. key.shift = mod & 4;
  384. key.meta = mod & 8;
  385. key.ctrl = mod & 16;
  386. b -= 32;
  387. if (b === 64) {
  388. key.action = 'wheelup';
  389. key.button = 'middle';
  390. } else if (b === 65) {
  391. key.action = 'wheeldown';
  392. key.button = 'middle';
  393. } else if (b === 3) {
  394. // Could also be a movement.
  395. key.action = 'mouseup';
  396. key.button = 'unknown';
  397. } else {
  398. key.action = 'mousedown';
  399. key.button =
  400. b === 0 ? 'left'
  401. : b === 1 ? 'middle'
  402. : b === 2 ? 'right'
  403. : 'unknown';
  404. }
  405. // It's a movement
  406. // Wrong
  407. //if (b > 32 && b < 64) {
  408. // delete key.button;
  409. // key.action = 'movement';
  410. //}
  411. // Probably a movement.
  412. if (key.action === 'mousedown' && key.button === 'unknown') {
  413. delete key.button;
  414. key.action = 'mousemove';
  415. }
  416. self.emit('keypress', null, key);
  417. self.emit('mouse', key);
  418. return;
  419. }
  420. // SGR
  421. if (parts = /^\x1b\[<(\d+;\d+;\d+)([mM])/.exec(s)) {
  422. var down = parts[2] === 'm'
  423. , parts = parts[1].split(';')
  424. , b = +parts[0]
  425. , x = +parts[1]
  426. , y = +parts[2];
  427. key.name = 'mouse';
  428. key.type = 'sgr';
  429. key.x = x;
  430. key.y = y;
  431. if (this.zero) key.x--, key.y--;
  432. b &= 3;
  433. // NOTE: Get mod. And wheel.
  434. key.action = down
  435. ? 'mousedown'
  436. : 'mouseup';
  437. key.button =
  438. b === 0 ? 'left'
  439. : b === 1 ? 'middle'
  440. : b === 2 ? 'right'
  441. : 'unknown';
  442. self.emit('keypress', null, key);
  443. self.emit('mouse', key);
  444. return;
  445. }
  446. // DEC
  447. // The xterm mouse documentation says there is a
  448. // `<` prefix, the DECRQLP says there is no prefix.
  449. if (parts = /^\x1b\[<(\d+;\d+;\d+;\d+)&w/.exec(s)) {
  450. var parts = parts[1].split(';')
  451. , b = +parts[0]
  452. , x = +parts[1]
  453. , y = +parts[2]
  454. , page = +parts[3];
  455. key.name = 'mouse';
  456. key.type = 'dec';
  457. key.button = b;
  458. key.x = x;
  459. key.y = y;
  460. if (this.zero) key.x--, key.y--;
  461. key.action = b === 3
  462. ? 'mouseup'
  463. : 'mousedown';
  464. key.button =
  465. b === 2 ? 'left'
  466. : b === 4 ? 'middle'
  467. : b === 6 ? 'right'
  468. : 'unknown';
  469. self.emit('keypress', null, key);
  470. self.emit('mouse', key);
  471. return;
  472. }
  473. // vt300
  474. if (parts = /^\x1b\[24([0135])~\[(\d+),(\d+)\]\r/.exec(s)) {
  475. var b = +parts[1]
  476. , x = +parts[2]
  477. , y = +parts[3];
  478. key.name = 'mouse';
  479. key.type = 'vt300';
  480. key.x = x;
  481. key.y = y;
  482. if (this.zero) key.x--, key.y--;
  483. key.action = 'mousedown';
  484. key.button =
  485. b === 1 ? 'left'
  486. : b === 2 ? 'middle'
  487. : b === 5 ? 'right'
  488. : 'unknown';
  489. self.emit('keypress', null, key);
  490. self.emit('mouse', key);
  491. return;
  492. }
  493. if (parts = /^\x1b\[(O|I)/.exec(s)) {
  494. key.action = parts[1] === 'I'
  495. ? 'focus'
  496. : 'blur';
  497. self.emit('mouse', key);
  498. self.emit(key.action);
  499. return;
  500. }
  501. };
  502. // All possible responses from the terminal
  503. Program.prototype.bindResponse = function() {
  504. if (this._boundResponse) return;
  505. this._boundResponse = true;
  506. var decoder = new StringDecoder('utf8')
  507. , self = this;
  508. this.on('data', function(data) {
  509. data = decoder.write(data);
  510. if (!data) return;
  511. self._bindResponse(data);
  512. });
  513. };
  514. Program.prototype._bindResponse = function(s) {
  515. var self = this
  516. , out = {}
  517. , parts;
  518. if (Buffer.isBuffer(s)) {
  519. if (s[0] > 127 && s[1] === undefined) {
  520. s[0] -= 128;
  521. s = '\x1b' + s.toString('utf-8');
  522. } else {
  523. s = s.toString('utf-8');
  524. }
  525. }
  526. // CSI P s c
  527. // Send Device Attributes (Primary DA).
  528. // CSI > P s c
  529. // Send Device Attributes (Secondary DA).
  530. if (parts = /^\x1b\[(\?|>)(\d*(?:;\d*)*)c/.exec(s)) {
  531. parts = parts[2].split(';').map(function(ch) {
  532. return +ch || 0;
  533. });
  534. out.event = 'device-attributes';
  535. out.code = 'DA';
  536. if (parts[1] === '?') {
  537. out.type = 'primary-attribute';
  538. // VT100-style params:
  539. if (parts[0] === 1 && parts[2] === 2) {
  540. out.term = 'vt100';
  541. out.advancedVideo = true;
  542. } else if (parts[0] === 1 && parts[2] === 0) {
  543. out.term = 'vt101';
  544. } else if (parts[0] === 6) {
  545. out.term = 'vt102';
  546. } else if (parts[0] === 60
  547. && parts[1] === 1 && parts[2] === 2
  548. && parts[3] === 6 && parts[4] === 8
  549. && parts[5] === 9 && parts[6] === 15) {
  550. out.term = 'vt220';
  551. } else {
  552. // VT200-style params:
  553. parts.forEach(function(attr) {
  554. switch (attr) {
  555. case 1:
  556. out.cols132 = true;
  557. break;
  558. case 2:
  559. out.printer = true;
  560. break;
  561. case 6:
  562. out.selectiveErase = true;
  563. break;
  564. case 8:
  565. out.userDefinedKeys = true;
  566. break;
  567. case 9:
  568. out.nationalReplacementCharsets = true;
  569. break;
  570. case 15:
  571. out.technicalCharacters = true;
  572. break;
  573. case 18:
  574. out.userWindows = true;
  575. break;
  576. case 21:
  577. out.horizontalScrolling = true;
  578. break;
  579. case 22:
  580. out.ansiColor = true;
  581. break;
  582. case 29:
  583. out.ansiTextLocator = true;
  584. break;
  585. }
  586. });
  587. }
  588. } else {
  589. out.type = 'secondary-attribute';
  590. switch (parts[0]) {
  591. case 0:
  592. out.term = 'vt100';
  593. break;
  594. case 1:
  595. out.term = 'vt220';
  596. break;
  597. case 2:
  598. out.term = 'vt240';
  599. break;
  600. case 18:
  601. out.term = 'vt330';
  602. break;
  603. case 19:
  604. out.term = 'vt340';
  605. break;
  606. case 24:
  607. out.term = 'vt320';
  608. break;
  609. case 41:
  610. out.term = 'vt420';
  611. break;
  612. case 61:
  613. out.term = 'vt510';
  614. break;
  615. case 64:
  616. out.term = 'vt520';
  617. break;
  618. case 65:
  619. out.term = 'vt525';
  620. break;
  621. }
  622. out.firmwareVersion = parts[1];
  623. out.romCartridgeRegistrationNumber = parts[2];
  624. }
  625. // LEGACY
  626. out.deviceAttributes = out;
  627. this.emit('response', out);
  628. this.emit('response ' + out.event, out);
  629. return;
  630. }
  631. // CSI Ps n Device Status Report (DSR).
  632. // Ps = 5 -> Status Report. Result (``OK'') is
  633. // CSI 0 n
  634. // CSI ? Ps n
  635. // Device Status Report (DSR, DEC-specific).
  636. // Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready).
  637. // or CSI ? 1 1 n (not ready).
  638. // Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked)
  639. // or CSI ? 2 1 n (locked).
  640. // Ps = 2 6 -> Report Keyboard status as
  641. // CSI ? 2 7 ; 1 ; 0 ; 0 n (North American).
  642. // The last two parameters apply to VT400 & up, and denote key-
  643. // board ready and LK01 respectively.
  644. // Ps = 5 3 -> Report Locator status as
  645. // CSI ? 5 3 n Locator available, if compiled-in, or
  646. // CSI ? 5 0 n No Locator, if not.
  647. if (parts = /^\x1b\[(\?)?(\d+)(?:;(\d+);(\d+);(\d+))?n/.exec(s)) {
  648. out.event = 'device-status';
  649. out.code = 'DSR';
  650. if (!parts[1] && parts[2] === '0' && !parts[3]) {
  651. out.type = 'device-status';
  652. out.status = 'OK';
  653. // LEGACY
  654. out.deviceStatus = out.status;
  655. this.emit('response', out);
  656. this.emit('response ' + out.event, out);
  657. return;
  658. }
  659. if (parts[1] && (parts[2] === '10' || parts[2] === '11') && !parts[3]) {
  660. out.type = 'printer-status';
  661. out.status = parts[2] === '10'
  662. ? 'ready'
  663. : 'not ready';
  664. // LEGACY
  665. out.printerStatus = out.status;
  666. this.emit('response', out);
  667. this.emit('response ' + out.event, out);
  668. return;
  669. }
  670. if (parts[1] && (parts[2] === '20' || parts[2] === '21') && !parts[3]) {
  671. out.type = 'udk-status';
  672. out.status = parts[2] === '20'
  673. ? 'unlocked'
  674. : 'locked';
  675. // LEGACY
  676. out.UDKStatus = out.status;
  677. this.emit('response', out);
  678. this.emit('response ' + out.event, out);
  679. return;
  680. }
  681. if (parts[1]
  682. && parts[2] === '27'
  683. && parts[3] === '1'
  684. && parts[4] === '0'
  685. && parts[5] === '0') {
  686. out.type = 'keyboard-status';
  687. out.status = 'OK';
  688. // LEGACY
  689. out.keyboardStatus = out.status;
  690. this.emit('response', out);
  691. this.emit('response ' + out.event, out);
  692. return;
  693. }
  694. if (parts[1] && (parts[2] === '53' || parts[2] === '50') && !parts[3]) {
  695. out.type = 'locator-status';
  696. out.status = parts[2] === '53'
  697. ? 'available'
  698. : 'unavailable';
  699. // LEGACY
  700. out.locator = out.status;
  701. this.emit('response', out);
  702. this.emit('response ' + out.event, out);
  703. return;
  704. }
  705. out.type = 'error';
  706. out.text = 'Unhandled: ' + JSON.stringify(parts);
  707. // LEGACY
  708. out.error = out.text;
  709. this.emit('response', out);
  710. this.emit('response ' + out.event, out);
  711. return;
  712. }
  713. // CSI Ps n Device Status Report (DSR).
  714. // Ps = 6 -> Report Cursor Position (CPR) [row;column].
  715. // Result is
  716. // CSI r ; c R
  717. // CSI ? Ps n
  718. // Device Status Report (DSR, DEC-specific).
  719. // Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI
  720. // ? r ; c R (assumes page is zero).
  721. if (parts = /^\x1b\[(\?)?(\d+);(\d+)R/.exec(s)) {
  722. out.event = 'device-status-report';
  723. out.code = 'DSR';
  724. out.type = 'cursor-status';
  725. out.status = {
  726. x: +parts[3],
  727. y: +parts[2],
  728. page: !parts[1] ? undefined : 0
  729. };
  730. out.x = out.status.x;
  731. out.y = out.status.y;
  732. out.page = out.status.page;
  733. // LEGACY
  734. out.cursor = out.status;
  735. this.emit('response', out);
  736. this.emit('response ' + out.event, out);
  737. return;
  738. }
  739. // CSI Ps ; Ps ; Ps t
  740. // Window manipulation (from dtterm, as well as extensions).
  741. // These controls may be disabled using the allowWindowOps
  742. // resource. Valid values for the first (and any additional
  743. // parameters) are:
  744. // Ps = 1 1 -> Report xterm window state. If the xterm window
  745. // is open (non-iconified), it returns CSI 1 t . If the xterm
  746. // window is iconified, it returns CSI 2 t .
  747. // Ps = 1 3 -> Report xterm window position. Result is CSI 3
  748. // ; x ; y t
  749. // Ps = 1 4 -> Report xterm window in pixels. Result is CSI
  750. // 4 ; height ; width t
  751. // Ps = 1 8 -> Report the size of the text area in characters.
  752. // Result is CSI 8 ; height ; width t
  753. // Ps = 1 9 -> Report the size of the screen in characters.
  754. // Result is CSI 9 ; height ; width t
  755. if (parts = /^\x1b\[(\d+)(?:;(\d+);(\d+))?t/.exec(s)) {
  756. out.event = 'window-manipulation';
  757. out.code = '';
  758. if ((parts[1] === '1' || parts[1] === '2') && !parts[2]) {
  759. out.type = 'window-state';
  760. out.state = parts[1] === '1'
  761. ? 'non-iconified'
  762. : 'iconified'
  763. // LEGACY
  764. out.windowState = out.state;
  765. this.emit('response', out);
  766. this.emit('response ' + out.event, out);
  767. return;
  768. }
  769. if (parts[1] === '3' && parts[2]) {
  770. out.type = 'window-position';
  771. out.position = {
  772. x: +parts[2],
  773. y: +parts[3]
  774. };
  775. out.x = out.position.x;
  776. out.y = out.position.y;
  777. // LEGACY
  778. out.windowPosition = out.position;
  779. this.emit('response', out);
  780. this.emit('response ' + out.event, out);
  781. return;
  782. }
  783. if (parts[1] === '4' && parts[2]) {
  784. out.type = 'window-size-pixels';
  785. out.size = {
  786. height: +parts[2],
  787. width: +parts[3]
  788. };
  789. out.height = out.size.height;
  790. out.width = out.size.width;
  791. // LEGACY
  792. out.windowSizePixels = out.size;
  793. this.emit('response', out);
  794. this.emit('response ' + out.event, out);
  795. return;
  796. }
  797. if (parts[1] === '8' && parts[2]) {
  798. out.type = 'textarea-size';
  799. out.size = {
  800. height: +parts[2],
  801. width: +parts[3]
  802. };
  803. out.height = out.size.height;
  804. out.width = out.size.width;
  805. // LEGACY
  806. out.textAreaSizeCharacters = out.size;
  807. this.emit('response', out);
  808. this.emit('response ' + out.event, out);
  809. return;
  810. }
  811. if (parts[1] === '9' && parts[2]) {
  812. out.type = 'screen-size';
  813. out.size = {
  814. height: +parts[2],
  815. width: +parts[3]
  816. };
  817. out.height = out.size.height;
  818. out.width = out.size.width;
  819. // LEGACY
  820. out.screenSizeCharacters = out.size;
  821. this.emit('response', out);
  822. this.emit('response ' + out.event, out);
  823. return;
  824. }
  825. out.type = 'error';
  826. out.text = 'Unhandled: ' + JSON.stringify(parts);
  827. // LEGACY
  828. out.error = out.text;
  829. this.emit('response', out);
  830. this.emit('response ' + out.event, out);
  831. return;
  832. }
  833. // CSI Ps ; Ps ; Ps t
  834. // Window manipulation (from dtterm, as well as extensions).
  835. // These controls may be disabled using the allowWindowOps
  836. // resource. Valid values for the first (and any additional
  837. // parameters) are:
  838. // Ps = 2 0 -> Report xterm window's icon label. Result is
  839. // OSC L label ST
  840. // Ps = 2 1 -> Report xterm window's title. Result is OSC l
  841. // label ST
  842. if (parts = /^\x1b\](l|L)([^\x07\x1b]*)(?:\x07|\x1b\\)/.exec(s)) {
  843. out.type = 'window-manipulation';
  844. out.code = '';
  845. if (parts[1] === 'L') {
  846. out.type = 'window-icon-label';
  847. out.text = parts[2];
  848. // LEGACY
  849. out.windowIconLabel = out.text;
  850. this.emit('response', out);
  851. this.emit('response ' + out.event, out);
  852. return;
  853. }
  854. if (parts[1] === 'l') {
  855. out.type = 'window-title';
  856. out.text = parts[2];
  857. // LEGACY
  858. out.windowTitle = out.text;
  859. this.emit('response', out);
  860. this.emit('response ' + out.event, out);
  861. return;
  862. }
  863. out.type = 'error';
  864. out.text = 'Unhandled: ' + JSON.stringify(parts);
  865. // LEGACY
  866. out.error = out.text;
  867. this.emit('response', out);
  868. this.emit('response ' + out.event, out);
  869. return;
  870. }
  871. // CSI Ps ' |
  872. // Request Locator Position (DECRQLP).
  873. // -> CSI Pe ; Pb ; Pr ; Pc ; Pp & w
  874. // Parameters are [event;button;row;column;page].
  875. // Valid values for the event:
  876. // Pe = 0 -> locator unavailable - no other parameters sent.
  877. // Pe = 1 -> request - xterm received a DECRQLP.
  878. // Pe = 2 -> left button down.
  879. // Pe = 3 -> left button up.
  880. // Pe = 4 -> middle button down.
  881. // Pe = 5 -> middle button up.
  882. // Pe = 6 -> right button down.
  883. // Pe = 7 -> right button up.
  884. // Pe = 8 -> M4 button down.
  885. // Pe = 9 -> M4 button up.
  886. // Pe = 1 0 -> locator outside filter rectangle.
  887. // ``button'' parameter is a bitmask indicating which buttons are
  888. // pressed:
  889. // Pb = 0 <- no buttons down.
  890. // Pb & 1 <- right button down.
  891. // Pb & 2 <- middle button down.
  892. // Pb & 4 <- left button down.
  893. // Pb & 8 <- M4 button down.
  894. // ``row'' and ``column'' parameters are the coordinates of the
  895. // locator position in the xterm window, encoded as ASCII deci-
  896. // mal.
  897. // The ``page'' parameter is not used by xterm, and will be omit-
  898. // ted.
  899. // NOTE:
  900. // This is already implemented in the _bindMouse
  901. // method, but it might make more sense here.
  902. // The xterm mouse documentation says there is a
  903. // `<` prefix, the DECRQLP says there is no prefix.
  904. if (parts = /^\x1b\[(\d+(?:;\d+){4})&w/.exec(s)) {
  905. parts = parts[1].split(';').map(function(ch) {
  906. return +ch;
  907. });
  908. out.event = 'locator-position';
  909. out.code = 'DECRQLP';
  910. switch (parts[0]) {
  911. case 0:
  912. out.status = 'locator-unavailable';
  913. break;
  914. case 1:
  915. out.status = 'request';
  916. break;
  917. case 2:
  918. out.status = 'left-button-down';
  919. break;
  920. case 3:
  921. out.status = 'left-button-up';
  922. break;
  923. case 4:
  924. out.status = 'middle-button-down';
  925. break;
  926. case 5:
  927. out.status = 'middle-button-up';
  928. break;
  929. case 6:
  930. out.status = 'right-button-down';
  931. break;
  932. case 7:
  933. out.status = 'right-button-up';
  934. break;
  935. case 8:
  936. out.status = 'm4-button-down';
  937. break;
  938. case 9:
  939. out.status = 'm4-button-up';
  940. break;
  941. case 10:
  942. out.status = 'locator-outside';
  943. break;
  944. }
  945. out.mask = parts[1];
  946. out.row = parts[2];
  947. out.col = parts[3];
  948. out.page = parts[4];
  949. // LEGACY
  950. out.locatorPosition = out;
  951. this.emit('response', out);
  952. this.emit('response ' + out.event, out);
  953. return;
  954. }
  955. };
  956. Program.prototype.receive = function(text, callback) {
  957. var listeners = (this._events && this._events['keypress']) || []
  958. , bak = listeners.slice()
  959. , self = this;
  960. if (!this.input.isRaw) {
  961. throw new Error('Input must be raw.');
  962. }
  963. listeners.length = 0;
  964. if (!callback) {
  965. callback = text;
  966. text = null;
  967. }
  968. this.input.once('data', function(data) {
  969. listeners.push.apply(listeners, bak);
  970. if (typeof data !== 'string') {
  971. data = data.toString('utf8');
  972. }
  973. return callback(null, data);
  974. });
  975. if (text != null) {
  976. return this._write(text);
  977. }
  978. };
  979. Program.prototype.response = function(name, text, callback) {
  980. if (arguments.length === 2) {
  981. callback = text;
  982. text = name;
  983. name = null;
  984. }
  985. if (!callback) {
  986. callback = function() {};
  987. }
  988. this.bindResponse();
  989. name = name
  990. ? 'response ' + name
  991. : 'response';
  992. this.once(name, function(event) {
  993. if (event.type === 'error') {
  994. return callback(new Error(event.event + ': ' + event.text));
  995. }
  996. return callback(null, event);
  997. });
  998. return this._write(text);
  999. };
  1000. Program.prototype._wrapCursor = function(nl) {
  1001. if (this.tput) {
  1002. //if (this.tput.bools.eat_newline_glitch) {
  1003. // return;
  1004. //}
  1005. if (this.tput.bools.auto_right_margin) {
  1006. this.x = 0;
  1007. this.y++;
  1008. return;
  1009. }
  1010. this.x--;
  1011. return;
  1012. }
  1013. this.x = 0;
  1014. this.y++;
  1015. };
  1016. // TODO: Make a private write for all of the methods here
  1017. // which does not call _parseChar. Make public write call
  1018. // _parseChar.
  1019. Program.prototype._parseChar = function(text, attr) {
  1020. for (var i = 0; i < text.length; i++) {
  1021. var cs = false;
  1022. while (text[i] === '\x1b') {
  1023. i++;
  1024. if (text[i] === '[' || text === ']') {
  1025. cs = true;
  1026. continue;
  1027. }
  1028. if (cs && (text[i] === ';' || (text[i] >= '0' && text[i] <= '9'))) {
  1029. continue;
  1030. }
  1031. if (text[i] === '\\' && text[i + 1] === '\x1b') i++;
  1032. i++;
  1033. cs = false;
  1034. break;
  1035. }
  1036. if (text[i] === '\n') {
  1037. if (this.tput
  1038. && this.tput.bools.eat_newline_glitch
  1039. && this.x >= this.cols) {
  1040. ;
  1041. } else {
  1042. this.x = 0;
  1043. this.y++;
  1044. }
  1045. } else if (text[i] === '\r') {
  1046. this.x = 0;
  1047. } else {
  1048. this.x++;
  1049. if (this.x >= this.cols) {
  1050. this._wrapCursor();
  1051. }
  1052. }
  1053. }
  1054. };
  1055. Program.prototype._buffer = function(text) {
  1056. if (this._exiting) {
  1057. this.flush();
  1058. this.output.write(text);
  1059. return;
  1060. }
  1061. if (this._buf) {
  1062. this._buf += text;
  1063. return;
  1064. }
  1065. this._buf = text;
  1066. process.nextTick(this._flush);
  1067. };
  1068. Program.prototype.flush = function(text) {
  1069. if (!this._buf) return;
  1070. this.output.write(this._buf);
  1071. this._buf = '';
  1072. };
  1073. Program.prototype._write = function(text) {
  1074. if (this.ret) return text;
  1075. if (this.useBuffer) {
  1076. return this._buffer(text);
  1077. }
  1078. return this.output.write(text);
  1079. };
  1080. Program.prototype.echo =
  1081. Program.prototype.write = function(text, attr) {
  1082. return attr
  1083. ? this._write(this.text(text, attr))
  1084. : this._write(text);
  1085. };
  1086. Program.prototype._ncoords = function() {
  1087. if (this.x < 0) this.x = 0;
  1088. else if (this.x >= this.cols) this.x = this.cols - 1;
  1089. if (this.y < 0) this.y = 0;
  1090. else if (this.y >= this.rows) this.y = this.rows - 1;
  1091. };
  1092. Program.prototype.setx = function(x) {
  1093. return this.cursorCharAbsolute(x);
  1094. // return this.charPosAbsolute(x);
  1095. };
  1096. Program.prototype.sety = function(y) {
  1097. return this.linePosAbsolute(y);
  1098. };
  1099. Program.prototype.move = function(x, y) {
  1100. return this.cursorPos(y, x);
  1101. };
  1102. // TODO: Fix cud and cuu calls.
  1103. Program.prototype.omove = function(x, y) {
  1104. if (!this.zero) {
  1105. x = (x || 1) - 1;
  1106. y = (y || 1) - 1;
  1107. } else {
  1108. x = x || 0;
  1109. y = y || 0;
  1110. }
  1111. if (y === this.y && x === this.x) {
  1112. return;
  1113. }
  1114. if (y === this.y) {
  1115. if (x > this.x) {
  1116. this.cuf(x - this.x);
  1117. } else if (x < this.x) {
  1118. this.cub(this.x - x);
  1119. }
  1120. } else if (x === this.x) {
  1121. if (y > this.y) {
  1122. this.cud(y - this.y);
  1123. } else if (y < this.y) {
  1124. this.cuu(this.y - y);
  1125. }
  1126. } else {
  1127. if (!this.zero) x++, y++;
  1128. this.cup(y, x);
  1129. }
  1130. };
  1131. Program.prototype.rsetx = function(x) {
  1132. // return this.HPositionRelative(x);
  1133. if (!x) return;
  1134. return x > 0
  1135. ? this.forward(x)
  1136. : this.back(-x);
  1137. };
  1138. Program.prototype.rsety = function(y) {
  1139. // return this.VPositionRelative(y);
  1140. if (!y) return;
  1141. return y > 0
  1142. ? this.up(y)
  1143. : this.down(-y);
  1144. };
  1145. Program.prototype.rmove = function(x, y) {
  1146. this.rsetx(x);
  1147. this.rsety(y);
  1148. };
  1149. Program.prototype.simpleInsert = function(ch, i, attr) {
  1150. return this._write(this.repeat(ch, i), attr);
  1151. };
  1152. Program.prototype.repeat = function(ch, i) {
  1153. if (!(i >= 0)) i = 0;
  1154. return Array(i + 1).join(ch);
  1155. };
  1156. /**
  1157. * Normal
  1158. */
  1159. //Program.prototype.pad =
  1160. Program.prototype.nul = function() {
  1161. //if (this.has('pad')) return this.put.pad();
  1162. return this._write('\200');
  1163. };
  1164. Program.prototype.bel =
  1165. Program.prototype.bell = function() {
  1166. if (this.has('bel')) return this.put.bel();
  1167. return this._write('\x07');
  1168. };
  1169. Program.prototype.vtab = function() {
  1170. this.y++;
  1171. this._ncoords();
  1172. return this._write('\x0b');
  1173. };
  1174. Program.prototype.ff =
  1175. Program.prototype.form = function() {
  1176. if (this.has('ff')) return this.put.ff();
  1177. return this._write('\x0c');
  1178. };
  1179. Program.prototype.kbs =
  1180. Program.prototype.backspace = function() {
  1181. this.x--;
  1182. this._ncoords();
  1183. if (this.has('kbs')) return this.put.kbs();
  1184. return this._write('\x08');
  1185. };
  1186. Program.prototype.ht =
  1187. Program.prototype.tab = function() {
  1188. this.x += 8;
  1189. this._ncoords();
  1190. if (this.has('ht')) return this.put.ht();
  1191. return this._write('\t');
  1192. };
  1193. Program.prototype.shiftOut = function() {
  1194. // if (this.has('S2')) return this.put.S2();
  1195. return this._write('\x0e');
  1196. };
  1197. Program.prototype.shiftIn = function() {
  1198. // if (this.has('S3')) return this.put.S3();
  1199. return this._write('\x0f');
  1200. };
  1201. Program.prototype.cr =
  1202. Program.prototype.return = function() {
  1203. this.x = 0;
  1204. if (this.has('cr')) return this.put.cr();
  1205. return this._write('\r');
  1206. };
  1207. Program.prototype.nel =
  1208. Program.prototype.newline =
  1209. Program.prototype.feed = function() {
  1210. if (this.tput && this.tput.bools.eat_newline_glitch && this.x >= this.cols) {
  1211. return;
  1212. }
  1213. this.x = 0;
  1214. this.y++;
  1215. this._ncoords();
  1216. if (this.has('nel')) return this.put.nel();
  1217. return this._write('\n');
  1218. };
  1219. /**
  1220. * Esc
  1221. */
  1222. // ESC D Index (IND is 0x84).
  1223. Program.prototype.ind =
  1224. Program.prototype.index = function() {
  1225. this.y++;
  1226. this._ncoords();
  1227. if (this.tput) return this.put.ind();
  1228. return this._write('\x1bD');
  1229. };
  1230. // ESC M Reverse Index (RI is 0x8d).
  1231. Program.prototype.ri =
  1232. Program.prototype.reverse =
  1233. Program.prototype.reverseIndex = function() {
  1234. this.y--;
  1235. this._ncoords();
  1236. if (this.tput) return this.put.ri();
  1237. return this._write('\x1bM');
  1238. };
  1239. // ESC E Next Line (NEL is 0x85).
  1240. Program.prototype.nextLine = function() {
  1241. this.y++;
  1242. this.x = 0;
  1243. this._ncoords();
  1244. if (this.has('nel')) return this.put.nel();
  1245. return this._write('\x1bE');
  1246. };
  1247. // ESC c Full Reset (RIS).
  1248. Program.prototype.reset = function() {
  1249. this.x = this.y = 0;
  1250. if (this.has('rs1') || this.has('ris')) {
  1251. return this.has('rs1')
  1252. ? this.put.rs1()
  1253. : this.put.ris();
  1254. }
  1255. return this._write('\x1bc');
  1256. };
  1257. // ESC H Tab Set (HTS is 0x88).
  1258. Program.prototype.tabSet = function() {
  1259. if (this.tput) return this.put.hts();
  1260. return this._write('\x1bH');
  1261. };
  1262. // ESC 7 Save Cursor (DECSC).
  1263. Program.prototype.sc =
  1264. Program.prototype.saveCursor = function(key) {
  1265. if (key) return this.lsaveCursor(key);
  1266. this.savedX = this.x || 0;
  1267. this.savedY = this.y || 0;
  1268. if (this.tput) return this.put.sc();
  1269. return this._write('\x1b7');
  1270. };
  1271. // ESC 8 Restore Cursor (DECRC).
  1272. Program.prototype.rc =
  1273. Program.prototype.restoreCursor = function(key, hide) {
  1274. if (key) return this.lrestoreCursor(key, hide);
  1275. this.x = this.savedX || 0;
  1276. this.y = this.savedY || 0;
  1277. if (this.tput) return this.put.rc();
  1278. return this._write('\x1b8');
  1279. };
  1280. // Save Cursor Locally
  1281. Program.prototype.lsaveCursor = function(key) {
  1282. var key = key || 'local';
  1283. this._saved = this._saved || {};
  1284. this._saved[key] = this._saved[key] || {};
  1285. this._saved[key].x = this.x;
  1286. this._saved[key].y = this.y;
  1287. this._saved[key].hidden = this.cursorHidden;
  1288. };
  1289. // Restore Cursor Locally
  1290. Program.prototype.lrestoreCursor = function(key, hide) {
  1291. var key = key || 'local', pos;
  1292. if (!this._saved || !this._saved[key]) return;
  1293. pos = this._saved[key];
  1294. //delete this._saved[key];
  1295. this.cup(pos.y, pos.x);
  1296. if (hide && pos.hidden !== this.cursorHidden) {
  1297. if (pos.hidden) {
  1298. this.hideCursor();
  1299. } else {
  1300. this.showCursor();
  1301. }
  1302. }
  1303. };
  1304. // ESC # 3 DEC line height/width
  1305. Program.prototype.lineHeight = function() {
  1306. return this._write('\x1b#');
  1307. };
  1308. // ESC (,),*,+,-,. Designate G0-G2 Character Set.
  1309. Program.prototype.charset = function(val, level) {
  1310. level = level || 0;
  1311. // See also:
  1312. // acs_chars / acsc / ac
  1313. // enter_alt_charset_mode / smacs / as
  1314. // exit_alt_charset_mode / rmacs / ae
  1315. // enter_pc_charset_mode / smpch / S2
  1316. // exit_pc_charset_mode / rmpch / S3
  1317. switch (level) {
  1318. case 0:
  1319. level = '(';
  1320. break;
  1321. case 1:
  1322. level = ')';
  1323. break;
  1324. case 2:
  1325. level = '*';
  1326. break;
  1327. case 3:
  1328. level = '+';
  1329. break;
  1330. }
  1331. var name = typeof val === 'string'
  1332. ? val.toLowerCase()
  1333. : val;
  1334. switch (name) {
  1335. case 'acs':
  1336. case 'scld': // DEC Special Character and Line Drawing Set.
  1337. if (this.tput) return this.put.smacs();
  1338. val = '0';
  1339. break;
  1340. case 'uk': // UK
  1341. val = 'A';
  1342. break;
  1343. case 'us': // United States (USASCII).
  1344. case 'usascii':
  1345. case 'ascii':
  1346. if (this.tput) return this.put.rmacs();
  1347. val = 'B';
  1348. break;
  1349. case 'dutch': // Dutch
  1350. val = '4';
  1351. break;
  1352. case 'finnish': // Finnish
  1353. val = 'C';
  1354. val = '5';
  1355. break;
  1356. case 'french': // French
  1357. val = 'R';
  1358. break;
  1359. case 'frenchcanadian': // FrenchCanadian
  1360. val = 'Q';
  1361. break;
  1362. case 'german': // German
  1363. val = 'K';
  1364. break;
  1365. case 'italian': // Italian
  1366. val = 'Y';
  1367. break;
  1368. case 'norwegiandanish': // NorwegianDanish
  1369. val = 'E';
  1370. val = '6';
  1371. break;
  1372. case 'spanish': // Spanish
  1373. val = 'Z';
  1374. break;
  1375. case 'swedish': // Swedish
  1376. val = 'H';
  1377. val = '7';
  1378. break;
  1379. case 'swiss': // Swiss
  1380. val = '=';
  1381. break;
  1382. case 'isolatin': // ISOLatin (actually /A)
  1383. val = '/A';
  1384. break;
  1385. default: // Default
  1386. if (this.tput) return this.put.rmacs();
  1387. val = 'B';
  1388. break;
  1389. }
  1390. return this._write('\x1b(' + val);
  1391. };
  1392. Program.prototype.enter_alt_charset_mode =
  1393. Program.prototype.as =
  1394. Program.prototype.smacs = function() {
  1395. return this.charset('acs');
  1396. };
  1397. Program.prototype.exit_alt_charset_mode =
  1398. Program.prototype.ae =
  1399. Program.prototype.rmacs = function() {
  1400. return this.charset('ascii');
  1401. };
  1402. // ESC N
  1403. // Single Shift Select of G2 Character Set
  1404. // ( SS2 is 0x8e). This affects next character only.
  1405. // ESC O
  1406. // Single Shift Select of G3 Character Set
  1407. // ( SS3 is 0x8f). This affects next character only.
  1408. // ESC n
  1409. // Invoke the G2 Character Set as GL (LS2).
  1410. // ESC o
  1411. // Invoke the G3 Character Set as GL (LS3).
  1412. // ESC |
  1413. // Invoke the G3 Character Set as GR (LS3R).
  1414. // ESC }
  1415. // Invoke the G2 Character Set as GR (LS2R).
  1416. // ESC ~
  1417. // Invoke the G1 Character Set as GR (LS1R).
  1418. Program.prototype.setG = function(val) {
  1419. // if (this.tput) return this.put.S2();
  1420. // if (this.tput) return this.put.S3();
  1421. switch (val) {
  1422. case 1:
  1423. val = '~'; // GR
  1424. break;
  1425. case 2:
  1426. val = 'n'; // GL
  1427. val = '}'; // GR
  1428. val = 'N'; // Next Char Only
  1429. break;
  1430. case 3:
  1431. val = 'o'; // GL
  1432. val = '|'; // GR
  1433. val = 'O'; // Next Char Only
  1434. break;
  1435. }
  1436. return this._write('\x1b' + val);
  1437. };
  1438. /**
  1439. * OSC
  1440. */
  1441. // OSC Ps ; Pt ST
  1442. // OSC Ps ; Pt BEL
  1443. // Set Text Parameters.
  1444. Program.prototype.setTitle = function(title) {
  1445. if (this.term('screen')) {
  1446. // Tmux pane
  1447. // if (process.env.TMUX) {
  1448. // return this._write('\x1b]2;' + title + '\x1b\\');
  1449. // }
  1450. return this._write('\x1bk' + title + '\x1b\\');
  1451. }
  1452. return this._write('\x1b]0;' + title + '\x07');
  1453. };
  1454. // OSC Ps ; Pt ST
  1455. // OSC Ps ; Pt BEL
  1456. // Reset colors
  1457. Program.prototype.resetColors = function(param) {
  1458. if (this.has('Cr')) {
  1459. return this.put.Cr(param);
  1460. }
  1461. return this._write('\x1b]112\x07');
  1462. //return this._write('\x1b]112;' + param + '\x07');
  1463. };
  1464. // OSC Ps ; Pt ST
  1465. // OSC Ps ; Pt BEL
  1466. // Change dynamic colors
  1467. Program.prototype.dynamicColors = function(param) {
  1468. if (this.has('Cs')) {
  1469. return this.put.Cs(param);
  1470. }
  1471. return this._write('\x1b]12;' + param + '\x07');
  1472. };
  1473. // OSC Ps ; Pt ST
  1474. // OSC Ps ; Pt BEL
  1475. // Sel data
  1476. Program.prototype.selData = function(a, b) {
  1477. if (this.has('Ms')) {
  1478. return this.put.Ms(a, b);
  1479. }
  1480. return this._write('\x1b]52;' + a + ';' + b + '\x07');
  1481. };
  1482. /**
  1483. * CSI
  1484. */
  1485. // CSI Ps A
  1486. // Cursor Up Ps Times (default = 1) (CUU).
  1487. Program.prototype.cuu =
  1488. Program.prototype.up =
  1489. Program.prototype.cursorUp = function(param) {
  1490. this.y -= param || 1;
  1491. this._ncoords();
  1492. if (this.tput) return this.put.cuu(param);
  1493. return this._write('\x1b[' + (param || '') + 'A');
  1494. };
  1495. // CSI Ps B
  1496. // Cursor Down Ps Times (default = 1) (CUD).
  1497. Program.prototype.cud =
  1498. Program.prototype.down =
  1499. Program.prototype.cursorDown = function(param) {
  1500. this.y += param || 1;
  1501. this._ncoords();
  1502. if (this.tput) return this.put.cud(param);
  1503. return this._write('\x1b[' + (param || '') + 'B');
  1504. };
  1505. // CSI Ps C
  1506. // Cursor Forward Ps Times (default = 1) (CUF).
  1507. Program.prototype.cuf =
  1508. Program.prototype.right =
  1509. Program.prototype.forward =
  1510. Program.prototype.cursorForward = function(param) {
  1511. this.x += param || 1;
  1512. this._ncoords();
  1513. if (this.tput) return this.put.cuf(param);
  1514. return this._write('\x1b[' + (param || '') + 'C');
  1515. };
  1516. // CSI Ps D
  1517. // Cursor Backward Ps Times (default = 1) (CUB).
  1518. Program.prototype.cub =
  1519. Program.prototype.left =
  1520. Program.prototype.back =
  1521. Program.prototype.cursorBackward = function(param) {
  1522. this.x -= param || 1;
  1523. this._ncoords();
  1524. if (this.tput) return this.put.cub(param);
  1525. return this._write('\x1b[' + (param || '') + 'D');
  1526. };
  1527. // CSI Ps ; Ps H
  1528. // Cursor Position [row;column] (default = [1,1]) (CUP).
  1529. Program.prototype.cup =
  1530. Program.prototype.pos =
  1531. Program.prototype.cursorPos = function(row, col) {
  1532. if (!this.zero) {
  1533. row = (row || 1) - 1;
  1534. col = (col || 1) - 1;
  1535. } else {
  1536. row = row || 0;
  1537. col = col || 0;
  1538. }
  1539. this.x = col;
  1540. this.y = row;
  1541. this._ncoords();
  1542. if (this.tput) return this.put.cup(row, col);
  1543. return this._write('\x1b[' + (row + 1) + ';' + (col + 1) + 'H');
  1544. };
  1545. // CSI Ps J Erase in Display (ED).
  1546. // Ps = 0 -> Erase Below (default).
  1547. // Ps = 1 -> Erase Above.
  1548. // Ps = 2 -> Erase All.
  1549. // Ps = 3 -> Erase Saved Lines (xterm).
  1550. // CSI ? Ps J
  1551. // Erase in Display (DECSED).
  1552. // Ps = 0 -> Selective Erase Below (default).
  1553. // Ps = 1 -> Selective Erase Above.
  1554. // Ps = 2 -> Selective Erase All.
  1555. Program.prototype.ed =
  1556. Program.prototype.eraseInDisplay = function(param) {
  1557. if (this.tput) {
  1558. switch (param) {
  1559. case 'above':
  1560. param = 1;
  1561. break;
  1562. case 'all':
  1563. param = 2;
  1564. break;
  1565. case 'saved':
  1566. param = 3;
  1567. break;
  1568. case 'below':
  1569. default:
  1570. param = 0;
  1571. break;
  1572. }
  1573. // extended tput.E3 = ^[[3;J
  1574. return this.put.ed(param);
  1575. }
  1576. switch (param) {
  1577. case 'above':
  1578. return this._write('\X1b[1J');
  1579. case 'all':
  1580. return this._write('\x1b[2J');
  1581. case 'saved':
  1582. return this._write('\x1b[3J');
  1583. case 'below':
  1584. default:
  1585. return this._write('\x1b[J');
  1586. }
  1587. };
  1588. Program.prototype.clear = function() {
  1589. this.x = 0;
  1590. this.y = 0;
  1591. if (this.tput) return this.put.clear();
  1592. return this._write('\x1b[H\x1b[J');
  1593. };
  1594. // CSI Ps K Erase in Line (EL).
  1595. // Ps = 0 -> Erase to Right (default).
  1596. // Ps = 1 -> Erase to Left.
  1597. // Ps = 2 -> Erase All.
  1598. // CSI ? Ps K
  1599. // Erase in Line (DECSEL).
  1600. // Ps = 0 -> Selective Erase to Right (default).
  1601. // Ps = 1 -> Selective Erase to Left.
  1602. // Ps = 2 -> Selective Erase All.
  1603. Program.prototype.el =
  1604. Program.prototype.eraseInLine = function(param) {
  1605. if (this.tput) {
  1606. //if (this.tput.back_color_erase) ...
  1607. switch (param) {
  1608. case 'left':
  1609. param = 1;
  1610. break;
  1611. case 'all':
  1612. param = 2;
  1613. break;
  1614. case 'right':
  1615. default:
  1616. param = 0;
  1617. break;
  1618. }
  1619. return this.put.el(param);
  1620. }
  1621. switch (param) {
  1622. case 'left':
  1623. return this._write('\x1b[1K');
  1624. case 'all':
  1625. return this._write('\x1b[2K');
  1626. case 'right':
  1627. default:
  1628. return this._write('\x1b[K');
  1629. }
  1630. };
  1631. // CSI Pm m Character Attributes (SGR).
  1632. // Ps = 0 -> Normal (default).
  1633. // Ps = 1 -> Bold.
  1634. // Ps = 4 -> Underlined.
  1635. // Ps = 5 -> Blink (appears as Bold).
  1636. // Ps = 7 -> Inverse.
  1637. // Ps = 8 -> Invisible, i.e., hidden (VT300).
  1638. // Ps = 2 2 -> Normal (neither bold nor faint).
  1639. // Ps = 2 4 -> Not underlined.
  1640. // Ps = 2 5 -> Steady (not blinking).
  1641. // Ps = 2 7 -> Positive (not inverse).
  1642. // Ps = 2 8 -> Visible, i.e., not hidden (VT300).
  1643. // Ps = 3 0 -> Set foreground color to Black.
  1644. // Ps = 3 1 -> Set foreground color to Red.
  1645. // Ps = 3 2 -> Set foreground color to Green.
  1646. // Ps = 3 3 -> Set foreground color to Yellow.
  1647. // Ps = 3 4 -> Set foreground color to Blue.
  1648. // Ps = 3 5 -> Set foreground color to Magenta.
  1649. // Ps = 3 6 -> Set foreground color to Cyan.
  1650. // Ps = 3 7 -> Set foreground color to White.
  1651. // Ps = 3 9 -> Set foreground color to default (original).
  1652. // Ps = 4 0 -> Set background color to Black.
  1653. // Ps = 4 1 -> Set background color to Red.
  1654. // Ps = 4 2 -> Set background color to Green.
  1655. // Ps = 4 3 -> Set background color to Yellow.
  1656. // Ps = 4 4 -> Set background color to Blue.
  1657. // Ps = 4 5 -> Set background color to Magenta.
  1658. // Ps = 4 6 -> Set background color to Cyan.
  1659. // Ps = 4 7 -> Set background color to White.
  1660. // Ps = 4 9 -> Set background color to default (original).
  1661. // If 16-color support is compiled, the following apply. Assume
  1662. // that xterm's resources are set so that the ISO color codes are
  1663. // the first 8 of a set of 16. Then the aixterm colors are the
  1664. // bright versions of the ISO colors:
  1665. // Ps = 9 0 -> Set foreground color to Black.
  1666. // Ps = 9 1 -> Set foreground color to Red.
  1667. // Ps = 9 2 -> Set foreground color to Green.
  1668. // Ps = 9 3 -> Set foreground color to Yellow.
  1669. // Ps = 9 4 -> Set foreground color to Blue.
  1670. // Ps = 9 5 -> Set foreground color to Magenta.
  1671. // Ps = 9 6 -> Set foreground color to Cyan.
  1672. // Ps = 9 7 -> Set foreground color to White.
  1673. // Ps = 1 0 0 -> Set background color to Black.
  1674. // Ps = 1 0 1 -> Set background color to Red.
  1675. // Ps = 1 0 2 -> Set background color to Green.
  1676. // Ps = 1 0 3 -> Set background color to Yellow.
  1677. // Ps = 1 0 4 -> Set background color to Blue.
  1678. // Ps = 1 0 5 -> Set background color to Magenta.
  1679. // Ps = 1 0 6 -> Set background color to Cyan.
  1680. // Ps = 1 0 7 -> Set background color to White.
  1681. // If xterm is compiled with the 16-color support disabled, it
  1682. // supports the following, from rxvt:
  1683. // Ps = 1 0 0 -> Set foreground and background color to
  1684. // default.
  1685. // If 88- or 256-color support is compiled, the following apply.
  1686. // Ps = 3 8 ; 5 ; Ps -> Set foreground color to the second
  1687. // Ps.
  1688. // Ps = 4 8 ; 5 ; Ps -> Set background color to the second
  1689. // Ps.
  1690. Program.prototype.sgr =
  1691. Program.prototype.attr =
  1692. Program.prototype.charAttributes = function(param, val) {
  1693. return this._write(this._attr(param, val));
  1694. };
  1695. Program.prototype.text = function(text, attr) {
  1696. return this._attr(attr, true) + text + this._attr(attr, false);
  1697. };
  1698. // NOTE: sun-color may not allow multiple params for SGR.
  1699. Program.prototype._attr = function(param, val) {
  1700. var self = this
  1701. , param
  1702. , parts
  1703. , color
  1704. , m;
  1705. if (Array.isArray(param)) {
  1706. parts = param;
  1707. param = parts[0] || 'normal';
  1708. } else {
  1709. param = param || 'normal';
  1710. parts = param.split(/\s*[,;]\s*/);
  1711. }
  1712. if (parts.length > 1) {
  1713. var used = {}
  1714. , out = [];
  1715. parts.forEach(function(part) {
  1716. part = self._attr(part, val).slice(2, -1);
  1717. if (part === '') return;
  1718. if (used[part]) return;
  1719. used[part] = true;
  1720. out.push(part);
  1721. });
  1722. return '\x1b[' + out.join(';') + 'm';
  1723. }
  1724. if (param.indexOf('no ') === 0) {
  1725. param = param.substring(3);
  1726. val = false;
  1727. } else if (param.indexOf('!') === 0) {
  1728. param = param.substring(1);
  1729. val = false;
  1730. }
  1731. switch (param) {
  1732. // attributes
  1733. case 'normal':
  1734. case 'default':
  1735. if (val === false) return '';
  1736. return '\x1b[m';
  1737. case 'bold':
  1738. return val === false
  1739. ? '\x1b[22m'
  1740. : '\x1b[1m';
  1741. case 'ul':
  1742. case 'underline':
  1743. case 'underlined':
  1744. return val === false
  1745. ? '\x1b[24m'
  1746. : '\x1b[4m';
  1747. case 'blink':
  1748. return val === false
  1749. ? '\x1b[25m'
  1750. : '\x1b[5m';
  1751. case 'inverse':
  1752. return val === false
  1753. ? '\x1b[27m'
  1754. : '\x1b[7m';
  1755. break;
  1756. case 'invisible':
  1757. return val === false
  1758. ? '\x1b[28m'
  1759. : '\x1b[8m';
  1760. // 8-color foreground
  1761. case 'black fg':
  1762. return val === false
  1763. ? '\x1b[39m'
  1764. : '\x1b[30m';
  1765. case 'red fg':
  1766. return val === false
  1767. ? '\x1b[39m'
  1768. : '\x1b[31m';
  1769. case 'green fg':
  1770. return val === false
  1771. ? '\x1b[39m'
  1772. : '\x1b[32m';
  1773. case 'yellow fg':
  1774. return val === false
  1775. ? '\x1b[39m'
  1776. : '\x1b[33m';
  1777. case 'blue fg':
  1778. return val === false
  1779. ? '\x1b[39m'
  1780. : '\x1b[34m';
  1781. case 'magenta fg':
  1782. return val === false
  1783. ? '\x1b[39m'
  1784. : '\x1b[35m';
  1785. case 'cyan fg':
  1786. return val === false
  1787. ? '\x1b[39m'
  1788. : '\x1b[36m';
  1789. case 'white fg':
  1790. return val === false
  1791. ? '\x1b[39m'
  1792. : '\x1b[37m';
  1793. case 'default fg':
  1794. if (val === false) return '';
  1795. return '\x1b[39m';
  1796. // 8-color background
  1797. case 'black bg':
  1798. return val === false
  1799. ? '\x1b[49m'
  1800. : '\x1b[40m';
  1801. case 'red bg':
  1802. return val === false
  1803. ? '\x1b[49m'
  1804. : '\x1b[41m';
  1805. case 'green bg':
  1806. return val === false
  1807. ? '\x1b[49m'
  1808. : '\x1b[42m';
  1809. case 'yellow bg':
  1810. return val === false
  1811. ? '\x1b[49m'
  1812. : '\x1b[43m';
  1813. case 'blue bg':
  1814. return val === false
  1815. ? '\x1b[49m'
  1816. : '\x1b[44m';
  1817. case 'magenta bg':
  1818. return val === false
  1819. ? '\x1b[49m'
  1820. : '\x1b[45m';
  1821. case 'cyan bg':
  1822. return val === false
  1823. ? '\x1b[49m'
  1824. : '\x1b[46m';
  1825. case 'white bg':
  1826. return val === false
  1827. ? '\x1b[49m'
  1828. : '\x1b[47m';
  1829. case 'default bg':
  1830. if (val === false) return '';
  1831. return '\x1b[49m';
  1832. // 16-color foreground
  1833. case 'light black fg':
  1834. return val === false
  1835. ? '\x1b[39m'
  1836. : '\x1b[90m';
  1837. case 'light red fg':
  1838. return val === false
  1839. ? '\x1b[39m'
  1840. : '\x1b[91m';
  1841. case 'light green fg':
  1842. return val === false
  1843. ? '\x1b[39m'
  1844. : '\x1b[92m';
  1845. case 'light yellow fg':
  1846. return val === false
  1847. ? '\x1b[39m'
  1848. : '\x1b[93m';
  1849. case 'light blue fg':
  1850. return val === false
  1851. ? '\x1b[39m'
  1852. : '\x1b[94m';
  1853. case 'light magenta fg':
  1854. return val === false
  1855. ? '\x1b[39m'
  1856. : '\x1b[95m';
  1857. case 'light cyan fg':
  1858. return val === false
  1859. ? '\x1b[39m'
  1860. : '\x1b[96m';
  1861. case 'light white fg':
  1862. return val === false
  1863. ? '\x1b[39m'
  1864. : '\x1b[97m';
  1865. // 16-color background
  1866. case 'light black bg':
  1867. return val === false
  1868. ? '\x1b[49m'
  1869. : '\x1b[100m';
  1870. case 'light red bg':
  1871. return val === false
  1872. ? '\x1b[49m'
  1873. : '\x1b[101m';
  1874. case 'light green bg':
  1875. return val === false
  1876. ? '\x1b[49m'
  1877. : '\x1b[102m';
  1878. case 'light yellow bg':
  1879. return val === false
  1880. ? '\x1b[49m'
  1881. : '\x1b[103m';
  1882. case 'light blue bg':
  1883. return val === false
  1884. ? '\x1b[49m'
  1885. : '\x1b[104m';
  1886. case 'light magenta bg':
  1887. return val === false
  1888. ? '\x1b[49m'
  1889. : '\x1b[105m';
  1890. case 'light cyan bg':
  1891. return val === false
  1892. ? '\x1b[49m'
  1893. : '\x1b[106m';
  1894. case 'light white bg':
  1895. return val === false
  1896. ? '\x1b[49m'
  1897. : '\x1b[107m';
  1898. // non-16-color rxvt default fg and bg
  1899. case 'default fg bg':
  1900. if (val === false) return '';
  1901. return this.term('rxvt')
  1902. ? '\x1b[100m'
  1903. : '\x1b[39;49m';
  1904. default:
  1905. // 256-color fg and bg
  1906. if (param[0] === '#') {
  1907. param = param.replace(/#(?:[0-9a-f]{3}){1,2}/i, colors.match);
  1908. }
  1909. m = /^(-?\d+) (fg|bg)$/.exec(param);
  1910. if (m) {
  1911. color = +m[1];
  1912. if (val === false || color === -1) {
  1913. return this._attr('default ' + m[2]);
  1914. }
  1915. if (color < 16 || (this.tput && this.tput.colors <= 16)) {
  1916. if (m[2] === 'fg') {
  1917. if (color < 8) {
  1918. color += 30;
  1919. } else if (color < 16) {
  1920. color += 90;
  1921. }
  1922. } else if (m[2] === 'bg') {
  1923. if (color < 8) {
  1924. color += 40;
  1925. } else if (color < 16) {
  1926. color += 100;
  1927. }
  1928. }
  1929. return '\x1b[' + color + 'm';
  1930. }
  1931. if (m[2] === 'fg') {
  1932. return '\x1b[38;5;' + color + 'm';
  1933. }
  1934. if (m[2] === 'bg') {
  1935. return '\x1b[48;5;' + color + 'm';
  1936. }
  1937. }
  1938. if (/^[\d;]*$/.test(param)) {
  1939. return '\x1b[' + param + 'm';
  1940. }
  1941. return null;
  1942. }
  1943. };
  1944. Program.prototype.fg =
  1945. Program.prototype.setForeground = function(color, val) {
  1946. color = color.split(/\s*[,;]\s*/).join(' fg, ') + ' fg';
  1947. return this.attr(color, val);
  1948. };
  1949. Program.prototype.bg =
  1950. Program.prototype.setBackground = function(color, val) {
  1951. color = color.split(/\s*[,;]\s*/).join(' bg, ') + ' bg';
  1952. return this.attr(color, val);
  1953. };
  1954. // CSI Ps n Device Status Report (DSR).
  1955. // Ps = 5 -> Status Report. Result (``OK'') is
  1956. // CSI 0 n
  1957. // Ps = 6 -> Report Cursor Position (CPR) [row;column].
  1958. // Result is
  1959. // CSI r ; c R
  1960. // CSI ? Ps n
  1961. // Device Status Report (DSR, DEC-specific).
  1962. // Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI
  1963. // ? r ; c R (assumes page is zero).
  1964. // Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready).
  1965. // or CSI ? 1 1 n (not ready).
  1966. // Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked)
  1967. // or CSI ? 2 1 n (locked).
  1968. // Ps = 2 6 -> Report Keyboard status as
  1969. // CSI ? 2 7 ; 1 ; 0 ; 0 n (North American).
  1970. // The last two parameters apply to VT400 & up, and denote key-
  1971. // board ready and LK01 respectively.
  1972. // Ps = 5 3 -> Report Locator status as
  1973. // CSI ? 5 3 n Locator available, if compiled-in, or
  1974. // CSI ? 5 0 n No Locator, if not.
  1975. Program.prototype.dsr =
  1976. Program.prototype.deviceStatus = function(param, callback, dec) {
  1977. if (dec) {
  1978. return this.response('device-status',
  1979. '\x1b[?' + (param || '0') + 'n', callback);
  1980. }
  1981. return this.response('device-status',
  1982. '\x1b[' + (param || '0') + 'n', callback);
  1983. };
  1984. Program.prototype.getCursor = function(callback) {
  1985. return this.deviceStatus('6', callback);
  1986. };
  1987. /**
  1988. * Additions
  1989. */
  1990. // CSI Ps @
  1991. // Insert Ps (Blank) Character(s) (default = 1) (ICH).
  1992. Program.prototype.ich =
  1993. Program.prototype.insertChars = function(param) {
  1994. this.x += param || 1;
  1995. this._ncoords();
  1996. if (this.tput) return this.put.ich(param);
  1997. return this._write('\x1b[' + (param || 1) + '@');
  1998. };
  1999. // CSI Ps E
  2000. // Cursor Next Line Ps Times (default = 1) (CNL).
  2001. // same as CSI Ps B ?
  2002. Program.prototype.cnl =
  2003. Program.prototype.cursorNextLine = function(param) {
  2004. this.y += param || 1;
  2005. this._ncoords();
  2006. return this._write('\x1b[' + (param || '') + 'E');
  2007. };
  2008. // CSI Ps F
  2009. // Cursor Preceding Line Ps Times (default = 1) (CNL).
  2010. // reuse CSI Ps A ?
  2011. Program.prototype.cpl =
  2012. Program.prototype.cursorPrecedingLine = function(param) {
  2013. this.y -= param || 1;
  2014. this._ncoords();
  2015. return this._write('\x1b[' + (param || '') + 'F');
  2016. };
  2017. // CSI Ps G
  2018. // Cursor Character Absolute [column] (default = [row,1]) (CHA).
  2019. Program.prototype.cha =
  2020. Program.prototype.cursorCharAbsolute = function(param) {
  2021. if (!this.zero) {
  2022. param = (param || 1) - 1;
  2023. } else {
  2024. param = param || 0;
  2025. }
  2026. this.x = param;
  2027. this.y = 0;
  2028. this._ncoords();
  2029. if (this.tput) return this.put.hpa(param);
  2030. return this._write('\x1b[' + (param + 1) + 'G');
  2031. };
  2032. // CSI Ps L
  2033. // Insert Ps Line(s) (default = 1) (IL).
  2034. Program.prototype.il =
  2035. Program.prototype.insertLines = function(param) {
  2036. if (this.tput) return this.put.il(param);
  2037. return this._write('\x1b[' + (param || '') + 'L');
  2038. };
  2039. // CSI Ps M
  2040. // Delete Ps Line(s) (default = 1) (DL).
  2041. Program.prototype.dl =
  2042. Program.prototype.deleteLines = function(param) {
  2043. if (this.tput) return this.put.dl(param);
  2044. return this._write('\x1b[' + (param || '') + 'M');
  2045. };
  2046. // CSI Ps P
  2047. // Delete Ps Character(s) (default = 1) (DCH).
  2048. Program.prototype.dch =
  2049. Program.prototype.deleteChars = function(param) {
  2050. if (this.tput) return this.put.dch(param);
  2051. return this._write('\x1b[' + (param || '') + 'P');
  2052. };
  2053. // CSI Ps X
  2054. // Erase Ps Character(s) (default = 1) (ECH).
  2055. Program.prototype.ech =
  2056. Program.prototype.eraseChars = function(param) {
  2057. if (this.tput) return this.put.ech(param);
  2058. return this._write('\x1b[' + (param || '') + 'X');
  2059. };
  2060. // CSI Pm ` Character Position Absolute
  2061. // [column] (default = [row,1]) (HPA).
  2062. Program.prototype.hpa =
  2063. Program.prototype.charPosAbsolute = function(param) {
  2064. this.x = param || 0;
  2065. this._ncoords();
  2066. if (this.tput) {
  2067. return this.put.hpa.apply(this.put, arguments);
  2068. }
  2069. var param = slice.call(arguments).join(';');
  2070. return this._write('\x1b[' + (param || '') + '`');
  2071. };
  2072. // 141 61 a * HPR -
  2073. // Horizontal Position Relative
  2074. // reuse CSI Ps C ?
  2075. Program.prototype.hpr =
  2076. Program.prototype.HPositionRelative = function(param) {
  2077. this.x += param || 1;
  2078. this._ncoords();
  2079. // Does not exist:
  2080. // if (this.tput) return this.put.hpr(param);
  2081. if (this.tput) return this.put.cuf(param);
  2082. return this._write('\x1b[' + (param || '') + 'a');
  2083. };
  2084. // CSI Ps c Send Device Attributes (Primary DA).
  2085. // Ps = 0 or omitted -> request attributes from terminal. The
  2086. // response depends on the decTerminalID resource setting.
  2087. // -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'')
  2088. // -> CSI ? 1 ; 0 c (``VT101 with No Options'')
  2089. // -> CSI ? 6 c (``VT102'')
  2090. // -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'')
  2091. // The VT100-style response parameters do not mean anything by
  2092. // themselves. VT220 parameters do, telling the host what fea-
  2093. // tures the terminal supports:
  2094. // Ps = 1 -> 132-columns.
  2095. // Ps = 2 -> Printer.
  2096. // Ps = 6 -> Selective erase.
  2097. // Ps = 8 -> User-defined keys.
  2098. // Ps = 9 -> National replacement character sets.
  2099. // Ps = 1 5 -> Technical characters.
  2100. // Ps = 2 2 -> ANSI color, e.g., VT525.
  2101. // Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode).
  2102. // CSI > Ps c
  2103. // Send Device Attributes (Secondary DA).
  2104. // Ps = 0 or omitted -> request the terminal's identification
  2105. // code. The response depends on the decTerminalID resource set-
  2106. // ting. It should apply only to VT220 and up, but xterm extends
  2107. // this to VT100.
  2108. // -> CSI > Pp ; Pv ; Pc c
  2109. // where Pp denotes the terminal type
  2110. // Pp = 0 -> ``VT100''.
  2111. // Pp = 1 -> ``VT220''.
  2112. // and Pv is the firmware version (for xterm, this was originally
  2113. // the XFree86 patch number, starting with 95). In a DEC termi-
  2114. // nal, Pc indicates the ROM cartridge registration number and is
  2115. // always zero.
  2116. // More information:
  2117. // xterm/charproc.c - line 2012, for more information.
  2118. // vim responds with ^[[?0c or ^[[?1c after the terminal's response (?)
  2119. Program.prototype.da =
  2120. Program.prototype.sendDeviceAttributes = function(param, callback) {
  2121. return this.response('device-attributes',
  2122. '\x1b[' + (param || '') + 'c', callback);
  2123. };
  2124. // CSI Pm d
  2125. // Line Position Absolute [row] (default = [1,column]) (VPA).
  2126. // NOTE: Can't find in terminfo, no idea why it has multiple params.
  2127. Program.prototype.vpa =
  2128. Program.prototype.linePosAbsolute = function(param) {
  2129. this.y = param || 1;
  2130. this._ncoords();
  2131. if (this.tput) {
  2132. return this.put.vpa.apply(this.put, arguments);
  2133. }
  2134. var param = slice.call(arguments).join(';');
  2135. return this._write('\x1b[' + (param || '') + 'd');
  2136. };
  2137. // 145 65 e * VPR - Vertical Position Relative
  2138. // reuse CSI Ps B ?
  2139. Program.prototype.vpr =
  2140. Program.prototype.VPositionRelative = function(param) {
  2141. this.y += param || 1;
  2142. this._ncoords();
  2143. // Does not exist:
  2144. // if (this.tput) return this.put.vpr(param);
  2145. if (this.tput) return this.put.cud(param);
  2146. return this._write('\x1b[' + (param || '') + 'e');
  2147. };
  2148. // CSI Ps ; Ps f
  2149. // Horizontal and Vertical Position [row;column] (default =
  2150. // [1,1]) (HVP).
  2151. Program.prototype.hvp =
  2152. Program.prototype.HVPosition = function(row, col) {
  2153. if (!this.zero) {
  2154. row = (row || 1) - 1;
  2155. col = (col || 1) - 1;
  2156. } else {
  2157. row = row || 0;
  2158. col = col || 0;
  2159. }
  2160. this.y = row;
  2161. this.x = col;
  2162. this._ncoords();
  2163. // Does not exist (?):
  2164. // if (this.tput) return this.put.hvp(row, col);
  2165. if (this.tput) return this.put.cup(row, col);
  2166. return this._write('\x1b[' + (row + 1) + ';' + (col + 1) + 'f');
  2167. };
  2168. // CSI Pm h Set Mode (SM).
  2169. // Ps = 2 -> Keyboard Action Mode (AM).
  2170. // Ps = 4 -> Insert Mode (IRM).
  2171. // Ps = 1 2 -> Send/receive (SRM).
  2172. // Ps = 2 0 -> Automatic Newline (LNM).
  2173. // CSI ? Pm h
  2174. // DEC Private Mode Set (DECSET).
  2175. // Ps = 1 -> Application Cursor Keys (DECCKM).
  2176. // Ps = 2 -> Designate USASCII for character sets G0-G3
  2177. // (DECANM), and set VT100 mode.
  2178. // Ps = 3 -> 132 Column Mode (DECCOLM).
  2179. // Ps = 4 -> Smooth (Slow) Scroll (DECSCLM).
  2180. // Ps = 5 -> Reverse Video (DECSCNM).
  2181. // Ps = 6 -> Origin Mode (DECOM).
  2182. // Ps = 7 -> Wraparound Mode (DECAWM).
  2183. // Ps = 8 -> Auto-repeat Keys (DECARM).
  2184. // Ps = 9 -> Send Mouse X & Y on button press. See the sec-
  2185. // tion Mouse Tracking.
  2186. // Ps = 1 0 -> Show toolbar (rxvt).
  2187. // Ps = 1 2 -> Start Blinking Cursor (att610).
  2188. // Ps = 1 8 -> Print form feed (DECPFF).
  2189. // Ps = 1 9 -> Set print extent to full screen (DECPEX).
  2190. // Ps = 2 5 -> Show Cursor (DECTCEM).
  2191. // Ps = 3 0 -> Show scrollbar (rxvt).
  2192. // Ps = 3 5 -> Enable font-shifting functions (rxvt).
  2193. // Ps = 3 8 -> Enter Tektronix Mode (DECTEK).
  2194. // Ps = 4 0 -> Allow 80 -> 132 Mode.
  2195. // Ps = 4 1 -> more(1) fix (see curses resource).
  2196. // Ps = 4 2 -> Enable Nation Replacement Character sets (DECN-
  2197. // RCM).
  2198. // Ps = 4 4 -> Turn On Margin Bell.
  2199. // Ps = 4 5 -> Reverse-wraparound Mode.
  2200. // Ps = 4 6 -> Start Logging. This is normally disabled by a
  2201. // compile-time option.
  2202. // Ps = 4 7 -> Use Alternate Screen Buffer. (This may be dis-
  2203. // abled by the titeInhibit resource).
  2204. // Ps = 6 6 -> Application keypad (DECNKM).
  2205. // Ps = 6 7 -> Backarrow key sends backspace (DECBKM).
  2206. // Ps = 1 0 0 0 -> Send Mouse X & Y on button press and
  2207. // release. See the section Mouse Tracking.
  2208. // Ps = 1 0 0 1 -> Use Hilite Mouse Tracking.
  2209. // Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking.
  2210. // Ps = 1 0 0 3 -> Use All Motion Mouse Tracking.
  2211. // Ps = 1 0 0 4 -> Send FocusIn/FocusOut events.
  2212. // Ps = 1 0 0 5 -> Enable Extended Mouse Mode.
  2213. // Ps = 1 0 1 0 -> Scroll to bottom on tty output (rxvt).
  2214. // Ps = 1 0 1 1 -> Scroll to bottom on key press (rxvt).
  2215. // Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit.
  2216. // (enables the eightBitInput resource).
  2217. // Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num-
  2218. // Lock keys. (This enables the numLock resource).
  2219. // Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This
  2220. // enables the metaSendsEscape resource).
  2221. // Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete
  2222. // key.
  2223. // Ps = 1 0 3 9 -> Send ESC when Alt modifies a key. (This
  2224. // enables the altSendsEscape resource).
  2225. // Ps = 1 0 4 0 -> Keep selection even if not highlighted.
  2226. // (This enables the keepSelection resource).
  2227. // Ps = 1 0 4 1 -> Use the CLIPBOARD selection. (This enables
  2228. // the selectToClipboard resource).
  2229. // Ps = 1 0 4 2 -> Enable Urgency window manager hint when
  2230. // Control-G is received. (This enables the bellIsUrgent
  2231. // resource).
  2232. // Ps = 1 0 4 3 -> Enable raising of the window when Control-G
  2233. // is received. (enables the popOnBell resource).
  2234. // Ps = 1 0 4 7 -> Use Alternate Screen Buffer. (This may be
  2235. // disabled by the titeInhibit resource).
  2236. // Ps = 1 0 4 8 -> Save cursor as in DECSC. (This may be dis-
  2237. // abled by the titeInhibit resource).
  2238. // Ps = 1 0 4 9 -> Save cursor as in DECSC and use Alternate
  2239. // Screen Buffer, clearing it first. (This may be disabled by
  2240. // the titeInhibit resource). This combines the effects of the 1
  2241. // 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based
  2242. // applications rather than the 4 7 mode.
  2243. // Ps = 1 0 5 0 -> Set terminfo/termcap function-key mode.
  2244. // Ps = 1 0 5 1 -> Set Sun function-key mode.
  2245. // Ps = 1 0 5 2 -> Set HP function-key mode.
  2246. // Ps = 1 0 5 3 -> Set SCO function-key mode.
  2247. // Ps = 1 0 6 0 -> Set legacy keyboard emulation (X11R6).
  2248. // Ps = 1 0 6 1 -> Set VT220 keyboard emulation.
  2249. // Ps = 2 0 0 4 -> Set bracketed paste mode.
  2250. // Modes:
  2251. // http://vt100.net/docs/vt220-rm/chapter4.html
  2252. Program.prototype.sm =
  2253. Program.prototype.setMode = function() {
  2254. var param = slice.call(arguments).join(';');
  2255. return this._write('\x1b[' + (param || '') + 'h');
  2256. };
  2257. Program.prototype.decset = function() {
  2258. var param = slice.call(arguments).join(';');
  2259. return this.setMode('?' + param);
  2260. };
  2261. Program.prototype.dectcem =
  2262. Program.prototype.cnorm =
  2263. Program.prototype.cvvis =
  2264. Program.prototype.showCursor = function() {
  2265. this.cursorHidden = false;
  2266. // NOTE: In xterm terminfo:
  2267. // cnorm stops blinking cursor
  2268. // cvvis starts blinking cursor
  2269. if (this.tput) return this.put.cnorm();
  2270. //if (this.tput) return this.put.cvvis();
  2271. // return this._write('\x1b[?12l\x1b[?25h'); // cursor_normal
  2272. // return this._write('\x1b[?12;25h'); // cursor_visible
  2273. return this.setMode('?25');
  2274. };
  2275. Program.prototype.alternate =
  2276. Program.prototype.smcup =
  2277. Program.prototype.alternateBuffer = function() {
  2278. this.isAlt = true;
  2279. if (this.tput) return this.put.smcup();
  2280. if (this.term('vt') || this.term('linux')) return;
  2281. return this.setMode('?1049');
  2282. };
  2283. // CSI Pm l Reset Mode (RM).
  2284. // Ps = 2 -> Keyboard Action Mode (AM).
  2285. // Ps = 4 -> Replace Mode (IRM).
  2286. // Ps = 1 2 -> Send/receive (SRM).
  2287. // Ps = 2 0 -> Normal Linefeed (LNM).
  2288. // CSI ? Pm l
  2289. // DEC Private Mode Reset (DECRST).
  2290. // Ps = 1 -> Normal Cursor Keys (DECCKM).
  2291. // Ps = 2 -> Designate VT52 mode (DECANM).
  2292. // Ps = 3 -> 80 Column Mode (DECCOLM).
  2293. // Ps = 4 -> Jump (Fast) Scroll (DECSCLM).
  2294. // Ps = 5 -> Normal Video (DECSCNM).
  2295. // Ps = 6 -> Normal Cursor Mode (DECOM).
  2296. // Ps = 7 -> No Wraparound Mode (DECAWM).
  2297. // Ps = 8 -> No Auto-repeat Keys (DECARM).
  2298. // Ps = 9 -> Don't send Mouse X & Y on button press.
  2299. // Ps = 1 0 -> Hide toolbar (rxvt).
  2300. // Ps = 1 2 -> Stop Blinking Cursor (att610).
  2301. // Ps = 1 8 -> Don't print form feed (DECPFF).
  2302. // Ps = 1 9 -> Limit print to scrolling region (DECPEX).
  2303. // Ps = 2 5 -> Hide Cursor (DECTCEM).
  2304. // Ps = 3 0 -> Don't show scrollbar (rxvt).
  2305. // Ps = 3 5 -> Disable font-shifting functions (rxvt).
  2306. // Ps = 4 0 -> Disallow 80 -> 132 Mode.
  2307. // Ps = 4 1 -> No more(1) fix (see curses resource).
  2308. // Ps = 4 2 -> Disable Nation Replacement Character sets (DEC-
  2309. // NRCM).
  2310. // Ps = 4 4 -> Turn Off Margin Bell.
  2311. // Ps = 4 5 -> No Reverse-wraparound Mode.
  2312. // Ps = 4 6 -> Stop Logging. (This is normally disabled by a
  2313. // compile-time option).
  2314. // Ps = 4 7 -> Use Normal Screen Buffer.
  2315. // Ps = 6 6 -> Numeric keypad (DECNKM).
  2316. // Ps = 6 7 -> Backarrow key sends delete (DECBKM).
  2317. // Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and
  2318. // release. See the section Mouse Tracking.
  2319. // Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking.
  2320. // Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking.
  2321. // Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking.
  2322. // Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events.
  2323. // Ps = 1 0 0 5 -> Disable Extended Mouse Mode.
  2324. // Ps = 1 0 1 0 -> Don't scroll to bottom on tty output
  2325. // (rxvt).
  2326. // Ps = 1 0 1 1 -> Don't scroll to bottom on key press (rxvt).
  2327. // Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables
  2328. // the eightBitInput resource).
  2329. // Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num-
  2330. // Lock keys. (This disables the numLock resource).
  2331. // Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key.
  2332. // (This disables the metaSendsEscape resource).
  2333. // Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad
  2334. // Delete key.
  2335. // Ps = 1 0 3 9 -> Don't send ESC when Alt modifies a key.
  2336. // (This disables the altSendsEscape resource).
  2337. // Ps = 1 0 4 0 -> Do not keep selection when not highlighted.
  2338. // (This disables the keepSelection resource).
  2339. // Ps = 1 0 4 1 -> Use the PRIMARY selection. (This disables
  2340. // the selectToClipboard resource).
  2341. // Ps = 1 0 4 2 -> Disable Urgency window manager hint when
  2342. // Control-G is received. (This disables the bellIsUrgent
  2343. // resource).
  2344. // Ps = 1 0 4 3 -> Disable raising of the window when Control-
  2345. // G is received. (This disables the popOnBell resource).
  2346. // Ps = 1 0 4 7 -> Use Normal Screen Buffer, clearing screen
  2347. // first if in the Alternate Screen. (This may be disabled by
  2348. // the titeInhibit resource).
  2349. // Ps = 1 0 4 8 -> Restore cursor as in DECRC. (This may be
  2350. // disabled by the titeInhibit resource).
  2351. // Ps = 1 0 4 9 -> Use Normal Screen Buffer and restore cursor
  2352. // as in DECRC. (This may be disabled by the titeInhibit
  2353. // resource). This combines the effects of the 1 0 4 7 and 1 0
  2354. // 4 8 modes. Use this with terminfo-based applications rather
  2355. // than the 4 7 mode.
  2356. // Ps = 1 0 5 0 -> Reset terminfo/termcap function-key mode.
  2357. // Ps = 1 0 5 1 -> Reset Sun function-key mode.
  2358. // Ps = 1 0 5 2 -> Reset HP function-key mode.
  2359. // Ps = 1 0 5 3 -> Reset SCO function-key mode.
  2360. // Ps = 1 0 6 0 -> Reset legacy keyboard emulation (X11R6).
  2361. // Ps = 1 0 6 1 -> Reset keyboard emulation to Sun/PC style.
  2362. // Ps = 2 0 0 4 -> Reset bracketed paste mode.
  2363. Program.prototype.rm =
  2364. Program.prototype.resetMode = function() {
  2365. var param = slice.call(arguments).join(';');
  2366. return this._write('\x1b[' + (param || '') + 'l');
  2367. };
  2368. Program.prototype.decrst = function() {
  2369. var param = slice.call(arguments).join(';');
  2370. return this.resetMode('?' + param);
  2371. };
  2372. Program.prototype.dectcemh =
  2373. Program.prototype.cursor_invisible =
  2374. Program.prototype.vi =
  2375. Program.prototype.civis =
  2376. Program.prototype.hideCursor = function() {
  2377. this.cursorHidden = true;
  2378. if (this.tput) return this.put.civis();
  2379. return this.resetMode('?25');
  2380. };
  2381. Program.prototype.rmcup =
  2382. Program.prototype.normalBuffer = function() {
  2383. this.isAlt = false;
  2384. if (this.tput) return this.put.rmcup();
  2385. return this.resetMode('?1049');
  2386. };
  2387. Program.prototype.enableMouse = function() {
  2388. if (this.term('rxvt-unicode')) {
  2389. return this.setMouse({
  2390. urxvtMouse: true,
  2391. allMotion: true
  2392. }, true);
  2393. }
  2394. if (this.term('linux')) {
  2395. return this.setMouse({
  2396. vt200Mouse: true
  2397. }, true);
  2398. }
  2399. if (this.term('xterm')
  2400. || this.term('screen')
  2401. || (this.tput && this.tput.strings.key_mouse)) {
  2402. return this.setMouse({
  2403. vt200Mouse: true,
  2404. utfMouse: true,
  2405. allMotion: true
  2406. }, true);
  2407. }
  2408. };
  2409. Program.prototype.disableMouse = function() {
  2410. if (!this._currentMouse) return;
  2411. var obj = {};
  2412. Object.keys(this._currentMouse).forEach(function(key) {
  2413. obj[key] = false;
  2414. });
  2415. return this.setMouse(obj, false);
  2416. };
  2417. // Set Mouse
  2418. Program.prototype.setMouse = function(opt, enable) {
  2419. if (opt.normalMouse != null) {
  2420. opt.vt200Mouse = opt.normalMouse;
  2421. opt.allMotion = opt.normalMouse;
  2422. }
  2423. if (opt.hiliteTracking != null) {
  2424. opt.vt200Hilite = opt.hiliteTracking;
  2425. }
  2426. if (enable) {
  2427. this._currentMouse = opt;
  2428. this.mouseEnabled = true;
  2429. } else {
  2430. delete this._currentMouse;
  2431. this.mouseEnabled = false;
  2432. }
  2433. // Make sure we're not a vtNNN
  2434. if (this.term('vt')) return;
  2435. // Ps = 9 -> Send Mouse X & Y on button press. See the sec-
  2436. // tion Mouse Tracking.
  2437. // Ps = 9 -> Don't send Mouse X & Y on button press.
  2438. // x10 mouse
  2439. if (opt.x10Mouse != null) {
  2440. if (opt.x10Mouse) this.setMode('?9');
  2441. else this.resetMode('?9');
  2442. }
  2443. // Ps = 1 0 0 0 -> Send Mouse X & Y on button press and
  2444. // release. See the section Mouse Tracking.
  2445. // Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and
  2446. // release. See the section Mouse Tracking.
  2447. // vt200 mouse
  2448. if (opt.vt200Mouse != null) {
  2449. if (opt.vt200Mouse) this.setMode('?1000');
  2450. else this.resetMode('?1000');
  2451. }
  2452. // Linux Console actually *does* support mouse reporting.
  2453. // See: `$ man console_codes`.
  2454. if (this.term('linux')) return;
  2455. // Ps = 1 0 0 1 -> Use Hilite Mouse Tracking.
  2456. // Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking.
  2457. if (opt.vt200Hilite != null) {
  2458. if (opt.vt200Hilite) this.setMode('?1001');
  2459. else this.resetMode('?1001');
  2460. }
  2461. // Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking.
  2462. // Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking.
  2463. // button event mouse
  2464. if (opt.cellMotion != null) {
  2465. if (opt.cellMotion) this.setMode('?1002');
  2466. else this.resetMode('?1002');
  2467. }
  2468. // Ps = 1 0 0 3 -> Use All Motion Mouse Tracking.
  2469. // Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking.
  2470. // any event mouse
  2471. if (opt.allMotion != null) {
  2472. if (opt.allMotion) this.setMode('?1003');
  2473. else this.resetMode('?1003');
  2474. }
  2475. // Ps = 1 0 0 4 -> Send FocusIn/FocusOut events.
  2476. // Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events.
  2477. if (opt.sendFocus != null) {
  2478. if (opt.sendFocus) this.setMode('?1004');
  2479. else this.resetMode('?1004');
  2480. }
  2481. // Ps = 1 0 0 5 -> Enable Extended Mouse Mode.
  2482. // Ps = 1 0 0 5 -> Disable Extended Mouse Mode.
  2483. if (opt.utfMouse != null) {
  2484. if (opt.utfMouse) this.setMode('?1005');
  2485. else this.resetMode('?1005');
  2486. }
  2487. // sgr mouse
  2488. if (opt.sgrMouse != null) {
  2489. if (opt.sgrMouse) this.setMode('?1006');
  2490. else this.resetMode('?1006');
  2491. }
  2492. // urxvt mouse
  2493. if (opt.urxvtMouse != null) {
  2494. if (opt.urxvtMouse) this.setMode('?1015');
  2495. else this.resetMode('?1015');
  2496. }
  2497. };
  2498. // CSI Ps ; Ps r
  2499. // Set Scrolling Region [top;bottom] (default = full size of win-
  2500. // dow) (DECSTBM).
  2501. // CSI ? Pm r
  2502. Program.prototype.decstbm =
  2503. Program.prototype.csr =
  2504. Program.prototype.setScrollRegion = function(top, bottom) {
  2505. if (!this.zero) {
  2506. top = (top || 1) - 1;
  2507. bottom = (bottom || this.rows) - 1;
  2508. } else {
  2509. top = top || 0;
  2510. bottom = bottom || (this.rows - 1);
  2511. }
  2512. this.scrollTop = top;
  2513. this.scrollBottom = bottom;
  2514. this.x = 0;
  2515. this.y = 0;
  2516. this._ncoords();
  2517. if (this.tput) return this.put.csr(top, bottom);
  2518. return this._write('\x1b[' + (top + 1) + ';' + (bottom + 1) + 'r');
  2519. };
  2520. // CSI s
  2521. // Save cursor (ANSI.SYS).
  2522. Program.prototype.scA =
  2523. Program.prototype.saveCursorA = function() {
  2524. this.savedX = this.x;
  2525. this.savedY = this.y;
  2526. if (this.tput) return this.put.sc();
  2527. return this._write('\x1b[s');
  2528. };
  2529. // CSI u
  2530. // Restore cursor (ANSI.SYS).
  2531. Program.prototype.rcA =
  2532. Program.prototype.restoreCursorA = function() {
  2533. this.x = this.savedX || 0;
  2534. this.y = this.savedY || 0;
  2535. if (this.tput) return this.put.rc();
  2536. return this._write('\x1b[u');
  2537. };
  2538. /**
  2539. * Lesser Used
  2540. */
  2541. // CSI Ps I
  2542. // Cursor Forward Tabulation Ps tab stops (default = 1) (CHT).
  2543. Program.prototype.cht =
  2544. Program.prototype.cursorForwardTab = function(param) {
  2545. this.x += 8;
  2546. this._ncoords();
  2547. if (this.tput) return this.put.tab(param);
  2548. return this._write('\x1b[' + (param || 1) + 'I');
  2549. };
  2550. // CSI Ps S Scroll up Ps lines (default = 1) (SU).
  2551. Program.prototype.su =
  2552. Program.prototype.scrollUp = function(param) {
  2553. this.y -= param || 1;
  2554. this._ncoords();
  2555. if (this.tput) return this.put.parm_index(param);
  2556. return this._write('\x1b[' + (param || 1) + 'S');
  2557. };
  2558. // CSI Ps T Scroll down Ps lines (default = 1) (SD).
  2559. Program.prototype.sd =
  2560. Program.prototype.scrollDown = function(param) {
  2561. this.y += param || 1;
  2562. this._ncoords();
  2563. if (this.tput) return this.put.parm_rindex(param);
  2564. return this._write('\x1b[' + (param || 1) + 'T');
  2565. };
  2566. // CSI Ps ; Ps ; Ps ; Ps ; Ps T
  2567. // Initiate highlight mouse tracking. Parameters are
  2568. // [func;startx;starty;firstrow;lastrow]. See the section Mouse
  2569. // Tracking.
  2570. Program.prototype.initMouseTracking = function() {
  2571. return this._write('\x1b[' + slice.call(arguments).join(';') + 'T');
  2572. };
  2573. // CSI > Ps; Ps T
  2574. // Reset one or more features of the title modes to the default
  2575. // value. Normally, "reset" disables the feature. It is possi-
  2576. // ble to disable the ability to reset features by compiling a
  2577. // different default for the title modes into xterm.
  2578. // Ps = 0 -> Do not set window/icon labels using hexadecimal.
  2579. // Ps = 1 -> Do not query window/icon labels using hexadeci-
  2580. // mal.
  2581. // Ps = 2 -> Do not set window/icon labels using UTF-8.
  2582. // Ps = 3 -> Do not query window/icon labels using UTF-8.
  2583. // (See discussion of "Title Modes").
  2584. Program.prototype.resetTitleModes = function() {
  2585. return this._write('\x1b[>' + slice.call(arguments).join(';') + 'T');
  2586. };
  2587. // CSI Ps Z Cursor Backward Tabulation Ps tab stops (default = 1) (CBT).
  2588. Program.prototype.cbt =
  2589. Program.prototype.cursorBackwardTab = function(param) {
  2590. this.x -= 8;
  2591. this._ncoords();
  2592. if (this.tput) return this.put.cbt(param);
  2593. return this._write('\x1b[' + (param || 1) + 'Z');
  2594. };
  2595. // CSI Ps b Repeat the preceding graphic character Ps times (REP).
  2596. Program.prototype.rep =
  2597. Program.prototype.repeatPrecedingCharacter = function(param) {
  2598. this.x += param || 1;
  2599. this._ncoords();
  2600. if (this.tput) return this.put.rep(param);
  2601. return this._write('\x1b[' + (param || 1) + 'b');
  2602. };
  2603. // CSI Ps g Tab Clear (TBC).
  2604. // Ps = 0 -> Clear Current Column (default).
  2605. // Ps = 3 -> Clear All.
  2606. // Potentially:
  2607. // Ps = 2 -> Clear Stops on Line.
  2608. // http://vt100.net/annarbor/aaa-ug/section6.html
  2609. Program.prototype.tbc =
  2610. Program.prototype.tabClear = function(param) {
  2611. if (this.tput) return this.put.tbc(param);
  2612. return this._write('\x1b[' + (param || 0) + 'g');
  2613. };
  2614. // CSI Pm i Media Copy (MC).
  2615. // Ps = 0 -> Print screen (default).
  2616. // Ps = 4 -> Turn off printer controller mode.
  2617. // Ps = 5 -> Turn on printer controller mode.
  2618. // CSI ? Pm i
  2619. // Media Copy (MC, DEC-specific).
  2620. // Ps = 1 -> Print line containing cursor.
  2621. // Ps = 4 -> Turn off autoprint mode.
  2622. // Ps = 5 -> Turn on autoprint mode.
  2623. // Ps = 1 0 -> Print composed display, ignores DECPEX.
  2624. // Ps = 1 1 -> Print all pages.
  2625. Program.prototype.mc =
  2626. Program.prototype.mediaCopy = function() {
  2627. return this._write('\x1b[' + slice.call(arguments).join(';') + 'i');
  2628. };
  2629. Program.prototype.print_screen =
  2630. Program.prototype.ps =
  2631. Program.prototype.mc0 = function() {
  2632. if (this.tput) return this.put.mc0();
  2633. return this.mc('0');
  2634. };
  2635. Program.prototype.prtr_on =
  2636. Program.prototype.po =
  2637. Program.prototype.mc5 = function() {
  2638. if (this.tput) return this.put.mc5();
  2639. return this.mc('5');
  2640. };
  2641. Program.prototype.prtr_off =
  2642. Program.prototype.pf =
  2643. Program.prototype.mc4 = function() {
  2644. if (this.tput) return this.put.mc4();
  2645. return this.mc('4');
  2646. };
  2647. Program.prototype.prtr_non =
  2648. Program.prototype.pO =
  2649. Program.prototype.mc5p = function() {
  2650. if (this.tput) return this.put.mc5p();
  2651. return this.mc('?5');
  2652. };
  2653. // CSI > Ps; Ps m
  2654. // Set or reset resource-values used by xterm to decide whether
  2655. // to construct escape sequences holding information about the
  2656. // modifiers pressed with a given key. The first parameter iden-
  2657. // tifies the resource to set/reset. The second parameter is the
  2658. // value to assign to the resource. If the second parameter is
  2659. // omitted, the resource is reset to its initial value.
  2660. // Ps = 1 -> modifyCursorKeys.
  2661. // Ps = 2 -> modifyFunctionKeys.
  2662. // Ps = 4 -> modifyOtherKeys.
  2663. // If no parameters are given, all resources are reset to their
  2664. // initial values.
  2665. Program.prototype.setResources = function() {
  2666. return this._write('\x1b[>' + slice.call(arguments).join(';') + 'm');
  2667. };
  2668. // CSI > Ps n
  2669. // Disable modifiers which may be enabled via the CSI > Ps; Ps m
  2670. // sequence. This corresponds to a resource value of "-1", which
  2671. // cannot be set with the other sequence. The parameter identi-
  2672. // fies the resource to be disabled:
  2673. // Ps = 1 -> modifyCursorKeys.
  2674. // Ps = 2 -> modifyFunctionKeys.
  2675. // Ps = 4 -> modifyOtherKeys.
  2676. // If the parameter is omitted, modifyFunctionKeys is disabled.
  2677. // When modifyFunctionKeys is disabled, xterm uses the modifier
  2678. // keys to make an extended sequence of functions rather than
  2679. // adding a parameter to each function key to denote the modi-
  2680. // fiers.
  2681. Program.prototype.disableModifiers = function(param) {
  2682. return this._write('\x1b[>' + (param || '') + 'n');
  2683. };
  2684. // CSI > Ps p
  2685. // Set resource value pointerMode. This is used by xterm to
  2686. // decide whether to hide the pointer cursor as the user types.
  2687. // Valid values for the parameter:
  2688. // Ps = 0 -> never hide the pointer.
  2689. // Ps = 1 -> hide if the mouse tracking mode is not enabled.
  2690. // Ps = 2 -> always hide the pointer. If no parameter is
  2691. // given, xterm uses the default, which is 1 .
  2692. Program.prototype.setPointerMode = function(param) {
  2693. return this._write('\x1b[>' + (param || '') + 'p');
  2694. };
  2695. // CSI ! p Soft terminal reset (DECSTR).
  2696. // http://vt100.net/docs/vt220-rm/table4-10.html
  2697. Program.prototype.decstr =
  2698. Program.prototype.rs2 =
  2699. Program.prototype.softReset = function() {
  2700. //if (this.tput) return this.put.init_2string();
  2701. //if (this.tput) return this.put.reset_2string();
  2702. if (this.tput) return this.put.rs2();
  2703. //return this._write('\x1b[!p');
  2704. //return this._write('\x1b[!p\x1b[?3;4l\x1b[4l\x1b>'); // init
  2705. return this._write('\x1b[!p\x1b[?3;4l\x1b[4l\x1b>'); // reset
  2706. };
  2707. // CSI Ps$ p
  2708. // Request ANSI mode (DECRQM). For VT300 and up, reply is
  2709. // CSI Ps; Pm$ y
  2710. // where Ps is the mode number as in RM, and Pm is the mode
  2711. // value:
  2712. // 0 - not recognized
  2713. // 1 - set
  2714. // 2 - reset
  2715. // 3 - permanently set
  2716. // 4 - permanently reset
  2717. Program.prototype.decrqm =
  2718. Program.prototype.requestAnsiMode = function(param) {
  2719. return this._write('\x1b[' + (param || '') + '$p');
  2720. };
  2721. // CSI ? Ps$ p
  2722. // Request DEC private mode (DECRQM). For VT300 and up, reply is
  2723. // CSI ? Ps; Pm$ p
  2724. // where Ps is the mode number as in DECSET, Pm is the mode value
  2725. // as in the ANSI DECRQM.
  2726. Program.prototype.decrqmp =
  2727. Program.prototype.requestPrivateMode = function(param) {
  2728. return this._write('\x1b[?' + (param || '') + '$p');
  2729. };
  2730. // CSI Ps ; Ps " p
  2731. // Set conformance level (DECSCL). Valid values for the first
  2732. // parameter:
  2733. // Ps = 6 1 -> VT100.
  2734. // Ps = 6 2 -> VT200.
  2735. // Ps = 6 3 -> VT300.
  2736. // Valid values for the second parameter:
  2737. // Ps = 0 -> 8-bit controls.
  2738. // Ps = 1 -> 7-bit controls (always set for VT100).
  2739. // Ps = 2 -> 8-bit controls.
  2740. Program.prototype.decscl =
  2741. Program.prototype.setConformanceLevel = function() {
  2742. return this._write('\x1b[' + slice.call(arguments).join(';') + '"p');
  2743. };
  2744. // CSI Ps q Load LEDs (DECLL).
  2745. // Ps = 0 -> Clear all LEDS (default).
  2746. // Ps = 1 -> Light Num Lock.
  2747. // Ps = 2 -> Light Caps Lock.
  2748. // Ps = 3 -> Light Scroll Lock.
  2749. // Ps = 2 1 -> Extinguish Num Lock.
  2750. // Ps = 2 2 -> Extinguish Caps Lock.
  2751. // Ps = 2 3 -> Extinguish Scroll Lock.
  2752. Program.prototype.decll =
  2753. Program.prototype.loadLEDs = function(param) {
  2754. return this._write('\x1b[' + (param || '') + 'q');
  2755. };
  2756. // CSI Ps SP q
  2757. // Set cursor style (DECSCUSR, VT520).
  2758. // Ps = 0 -> blinking block.
  2759. // Ps = 1 -> blinking block (default).
  2760. // Ps = 2 -> steady block.
  2761. // Ps = 3 -> blinking underline.
  2762. // Ps = 4 -> steady underline.
  2763. Program.prototype.decscusr =
  2764. Program.prototype.setCursorStyle = function(param) {
  2765. switch (param) {
  2766. case 'blinking block':
  2767. param = 1;
  2768. break;
  2769. case 'block':
  2770. case 'steady block':
  2771. param = 2;
  2772. break;
  2773. case 'blinking underline':
  2774. param = 3;
  2775. break;
  2776. case 'underline':
  2777. case 'steady underline':
  2778. param = 4;
  2779. break;
  2780. case 'blinking bar':
  2781. param = 5;
  2782. break;
  2783. case 'bar':
  2784. case 'steady bar':
  2785. param = 6;
  2786. break;
  2787. }
  2788. if (param === 2 && this.has('Se')) {
  2789. return this.put.Se();
  2790. }
  2791. if (this.has('Ss')) {
  2792. return this.put.Ss(param);
  2793. }
  2794. return this._write('\x1b[' + (param || 1) + ' q');
  2795. };
  2796. // CSI Ps " q
  2797. // Select character protection attribute (DECSCA). Valid values
  2798. // for the parameter:
  2799. // Ps = 0 -> DECSED and DECSEL can erase (default).
  2800. // Ps = 1 -> DECSED and DECSEL cannot erase.
  2801. // Ps = 2 -> DECSED and DECSEL can erase.
  2802. Program.prototype.decsca =
  2803. Program.prototype.setCharProtectionAttr = function(param) {
  2804. return this._write('\x1b[' + (param || 0) + '"q');
  2805. };
  2806. // CSI ? Pm r
  2807. // Restore DEC Private Mode Values. The value of Ps previously
  2808. // saved is restored. Ps values are the same as for DECSET.
  2809. Program.prototype.restorePrivateValues = function() {
  2810. return this._write('\x1b[?' + slice.call(arguments).join(';') + 'r');
  2811. };
  2812. // CSI Pt; Pl; Pb; Pr; Ps$ r
  2813. // Change Attributes in Rectangular Area (DECCARA), VT400 and up.
  2814. // Pt; Pl; Pb; Pr denotes the rectangle.
  2815. // Ps denotes the SGR attributes to change: 0, 1, 4, 5, 7.
  2816. // NOTE: xterm doesn't enable this code by default.
  2817. Program.prototype.deccara =
  2818. Program.prototype.setAttrInRectangle = function() {
  2819. return this._write('\x1b[' + slice.call(arguments).join(';') + '$r');
  2820. };
  2821. // CSI ? Pm s
  2822. // Save DEC Private Mode Values. Ps values are the same as for
  2823. // DECSET.
  2824. Program.prototype.savePrivateValues = function(params) {
  2825. return this._write('\x1b[?' + slice.call(arguments).join(';') + 's');
  2826. };
  2827. // CSI Ps ; Ps ; Ps t
  2828. // Window manipulation (from dtterm, as well as extensions).
  2829. // These controls may be disabled using the allowWindowOps
  2830. // resource. Valid values for the first (and any additional
  2831. // parameters) are:
  2832. // Ps = 1 -> De-iconify window.
  2833. // Ps = 2 -> Iconify window.
  2834. // Ps = 3 ; x ; y -> Move window to [x, y].
  2835. // Ps = 4 ; height ; width -> Resize the xterm window to
  2836. // height and width in pixels.
  2837. // Ps = 5 -> Raise the xterm window to the front of the stack-
  2838. // ing order.
  2839. // Ps = 6 -> Lower the xterm window to the bottom of the
  2840. // stacking order.
  2841. // Ps = 7 -> Refresh the xterm window.
  2842. // Ps = 8 ; height ; width -> Resize the text area to
  2843. // [height;width] in characters.
  2844. // Ps = 9 ; 0 -> Restore maximized window.
  2845. // Ps = 9 ; 1 -> Maximize window (i.e., resize to screen
  2846. // size).
  2847. // Ps = 1 0 ; 0 -> Undo full-screen mode.
  2848. // Ps = 1 0 ; 1 -> Change to full-screen.
  2849. // Ps = 1 1 -> Report xterm window state. If the xterm window
  2850. // is open (non-iconified), it returns CSI 1 t . If the xterm
  2851. // window is iconified, it returns CSI 2 t .
  2852. // Ps = 1 3 -> Report xterm window position. Result is CSI 3
  2853. // ; x ; y t
  2854. // Ps = 1 4 -> Report xterm window in pixels. Result is CSI
  2855. // 4 ; height ; width t
  2856. // Ps = 1 8 -> Report the size of the text area in characters.
  2857. // Result is CSI 8 ; height ; width t
  2858. // Ps = 1 9 -> Report the size of the screen in characters.
  2859. // Result is CSI 9 ; height ; width t
  2860. // Ps = 2 0 -> Report xterm window's icon label. Result is
  2861. // OSC L label ST
  2862. // Ps = 2 1 -> Report xterm window's title. Result is OSC l
  2863. // label ST
  2864. // Ps = 2 2 ; 0 -> Save xterm icon and window title on
  2865. // stack.
  2866. // Ps = 2 2 ; 1 -> Save xterm icon title on stack.
  2867. // Ps = 2 2 ; 2 -> Save xterm window title on stack.
  2868. // Ps = 2 3 ; 0 -> Restore xterm icon and window title from
  2869. // stack.
  2870. // Ps = 2 3 ; 1 -> Restore xterm icon title from stack.
  2871. // Ps = 2 3 ; 2 -> Restore xterm window title from stack.
  2872. // Ps >= 2 4 -> Resize to Ps lines (DECSLPP).
  2873. Program.prototype.manipulateWindow = function() {
  2874. var args = slice.call(arguments);
  2875. var callback = typeof args[args.length-1] === 'function'
  2876. ? args.pop()
  2877. : function() {};
  2878. return this.response('window-manipulation',
  2879. '\x1b[' + args.join(';') + 't', callback);
  2880. };
  2881. Program.prototype.getWindowSize = function(callback) {
  2882. return this.manipulateWindow('18', callback);
  2883. };
  2884. // CSI Pt; Pl; Pb; Pr; Ps$ t
  2885. // Reverse Attributes in Rectangular Area (DECRARA), VT400 and
  2886. // up.
  2887. // Pt; Pl; Pb; Pr denotes the rectangle.
  2888. // Ps denotes the attributes to reverse, i.e., 1, 4, 5, 7.
  2889. // NOTE: xterm doesn't enable this code by default.
  2890. Program.prototype.decrara =
  2891. Program.prototype.reverseAttrInRectangle = function(params) {
  2892. return this._write('\x1b[' + slice.call(arguments).join(';') + '$t');
  2893. };
  2894. // CSI > Ps; Ps t
  2895. // Set one or more features of the title modes. Each parameter
  2896. // enables a single feature.
  2897. // Ps = 0 -> Set window/icon labels using hexadecimal.
  2898. // Ps = 1 -> Query window/icon labels using hexadecimal.
  2899. // Ps = 2 -> Set window/icon labels using UTF-8.
  2900. // Ps = 3 -> Query window/icon labels using UTF-8. (See dis-
  2901. // cussion of "Title Modes")
  2902. Program.prototype.setTitleModeFeature = function(params) {
  2903. return this._write('\x1b[>' + slice.call(arguments).join(';') + 't');
  2904. };
  2905. // CSI Ps SP t
  2906. // Set warning-bell volume (DECSWBV, VT520).
  2907. // Ps = 0 or 1 -> off.
  2908. // Ps = 2 , 3 or 4 -> low.
  2909. // Ps = 5 , 6 , 7 , or 8 -> high.
  2910. Program.prototype.decswbv =
  2911. Program.prototype.setWarningBellVolume = function(params) {
  2912. return this._write('\x1b[' + (param || '') + ' t');
  2913. };
  2914. // CSI Ps SP u
  2915. // Set margin-bell volume (DECSMBV, VT520).
  2916. // Ps = 1 -> off.
  2917. // Ps = 2 , 3 or 4 -> low.
  2918. // Ps = 0 , 5 , 6 , 7 , or 8 -> high.
  2919. Program.prototype.decsmbv =
  2920. Program.prototype.setMarginBellVolume = function(params) {
  2921. return this._write('\x1b[' + (param || '') + ' u');
  2922. };
  2923. // CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v
  2924. // Copy Rectangular Area (DECCRA, VT400 and up).
  2925. // Pt; Pl; Pb; Pr denotes the rectangle.
  2926. // Pp denotes the source page.
  2927. // Pt; Pl denotes the target location.
  2928. // Pp denotes the target page.
  2929. // NOTE: xterm doesn't enable this code by default.
  2930. Program.prototype.deccra =
  2931. Program.prototype.copyRectangle = function(params) {
  2932. return this._write('\x1b[' + slice.call(arguments).join(';') + '$v');
  2933. };
  2934. // CSI Pt ; Pl ; Pb ; Pr ' w
  2935. // Enable Filter Rectangle (DECEFR), VT420 and up.
  2936. // Parameters are [top;left;bottom;right].
  2937. // Defines the coordinates of a filter rectangle and activates
  2938. // it. Anytime the locator is detected outside of the filter
  2939. // rectangle, an outside rectangle event is generated and the
  2940. // rectangle is disabled. Filter rectangles are always treated
  2941. // as "one-shot" events. Any parameters that are omitted default
  2942. // to the current locator position. If all parameters are omit-
  2943. // ted, any locator motion will be reported. DECELR always can-
  2944. // cels any prevous rectangle definition.
  2945. Program.prototype.decefr =
  2946. Program.prototype.enableFilterRectangle = function(params) {
  2947. return this._write('\x1b[' + slice.call(arguments).join(';') + '\'w');
  2948. };
  2949. // CSI Ps x Request Terminal Parameters (DECREQTPARM).
  2950. // if Ps is a "0" (default) or "1", and xterm is emulating VT100,
  2951. // the control sequence elicits a response of the same form whose
  2952. // parameters describe the terminal:
  2953. // Ps -> the given Ps incremented by 2.
  2954. // Pn = 1 <- no parity.
  2955. // Pn = 1 <- eight bits.
  2956. // Pn = 1 <- 2 8 transmit 38.4k baud.
  2957. // Pn = 1 <- 2 8 receive 38.4k baud.
  2958. // Pn = 1 <- clock multiplier.
  2959. // Pn = 0 <- STP flags.
  2960. Program.prototype.decreqtparm =
  2961. Program.prototype.requestParameters = function(params) {
  2962. return this._write('\x1b[' + (param || 0) + 'x');
  2963. };
  2964. // CSI Ps x Select Attribute Change Extent (DECSACE).
  2965. // Ps = 0 -> from start to end position, wrapped.
  2966. // Ps = 1 -> from start to end position, wrapped.
  2967. // Ps = 2 -> rectangle (exact).
  2968. Program.prototype.decsace =
  2969. Program.prototype.selectChangeExtent = function(params) {
  2970. return this._write('\x1b[' + (param || 0) + 'x');
  2971. };
  2972. // CSI Pc; Pt; Pl; Pb; Pr$ x
  2973. // Fill Rectangular Area (DECFRA), VT420 and up.
  2974. // Pc is the character to use.
  2975. // Pt; Pl; Pb; Pr denotes the rectangle.
  2976. // NOTE: xterm doesn't enable this code by default.
  2977. Program.prototype.decfra =
  2978. Program.prototype.fillRectangle = function(params) {
  2979. return this._write('\x1b[' + slice.call(arguments).join(';') + '$x');
  2980. };
  2981. // CSI Ps ; Pu ' z
  2982. // Enable Locator Reporting (DECELR).
  2983. // Valid values for the first parameter:
  2984. // Ps = 0 -> Locator disabled (default).
  2985. // Ps = 1 -> Locator enabled.
  2986. // Ps = 2 -> Locator enabled for one report, then disabled.
  2987. // The second parameter specifies the coordinate unit for locator
  2988. // reports.
  2989. // Valid values for the second parameter:
  2990. // Pu = 0 <- or omitted -> default to character cells.
  2991. // Pu = 1 <- device physical pixels.
  2992. // Pu = 2 <- character cells.
  2993. Program.prototype.decelr =
  2994. Program.prototype.enableLocatorReporting = function(params) {
  2995. return this._write('\x1b[' + slice.call(arguments).join(';') + '\'z');
  2996. };
  2997. // CSI Pt; Pl; Pb; Pr$ z
  2998. // Erase Rectangular Area (DECERA), VT400 and up.
  2999. // Pt; Pl; Pb; Pr denotes the rectangle.
  3000. // NOTE: xterm doesn't enable this code by default.
  3001. Program.prototype.decera =
  3002. Program.prototype.eraseRectangle = function(params) {
  3003. return this._write('\x1b[' + slice.call(arguments).join(';') + '$z');
  3004. };
  3005. // CSI Pm ' {
  3006. // Select Locator Events (DECSLE).
  3007. // Valid values for the first (and any additional parameters)
  3008. // are:
  3009. // Ps = 0 -> only respond to explicit host requests (DECRQLP).
  3010. // (This is default). It also cancels any filter
  3011. // rectangle.
  3012. // Ps = 1 -> report button down transitions.
  3013. // Ps = 2 -> do not report button down transitions.
  3014. // Ps = 3 -> report button up transitions.
  3015. // Ps = 4 -> do not report button up transitions.
  3016. Program.prototype.decsle =
  3017. Program.prototype.setLocatorEvents = function(params) {
  3018. return this._write('\x1b[' + slice.call(arguments).join(';') + '\'{');
  3019. };
  3020. // CSI Pt; Pl; Pb; Pr$ {
  3021. // Selective Erase Rectangular Area (DECSERA), VT400 and up.
  3022. // Pt; Pl; Pb; Pr denotes the rectangle.
  3023. Program.prototype.decsera =
  3024. Program.prototype.selectiveEraseRectangle = function(params) {
  3025. return this._write('\x1b[' + slice.call(arguments).join(';') + '${');
  3026. };
  3027. // CSI Ps ' |
  3028. // Request Locator Position (DECRQLP).
  3029. // Valid values for the parameter are:
  3030. // Ps = 0 , 1 or omitted -> transmit a single DECLRP locator
  3031. // report.
  3032. // If Locator Reporting has been enabled by a DECELR, xterm will
  3033. // respond with a DECLRP Locator Report. This report is also
  3034. // generated on button up and down events if they have been
  3035. // enabled with a DECSLE, or when the locator is detected outside
  3036. // of a filter rectangle, if filter rectangles have been enabled
  3037. // with a DECEFR.
  3038. // -> CSI Pe ; Pb ; Pr ; Pc ; Pp & w
  3039. // Parameters are [event;button;row;column;page].
  3040. // Valid values for the event:
  3041. // Pe = 0 -> locator unavailable - no other parameters sent.
  3042. // Pe = 1 -> request - xterm received a DECRQLP.
  3043. // Pe = 2 -> left button down.
  3044. // Pe = 3 -> left button up.
  3045. // Pe = 4 -> middle button down.
  3046. // Pe = 5 -> middle button up.
  3047. // Pe = 6 -> right button down.
  3048. // Pe = 7 -> right button up.
  3049. // Pe = 8 -> M4 button down.
  3050. // Pe = 9 -> M4 button up.
  3051. // Pe = 1 0 -> locator outside filter rectangle.
  3052. // ``button'' parameter is a bitmask indicating which buttons are
  3053. // pressed:
  3054. // Pb = 0 <- no buttons down.
  3055. // Pb & 1 <- right button down.
  3056. // Pb & 2 <- middle button down.
  3057. // Pb & 4 <- left button down.
  3058. // Pb & 8 <- M4 button down.
  3059. // ``row'' and ``column'' parameters are the coordinates of the
  3060. // locator position in the xterm window, encoded as ASCII deci-
  3061. // mal.
  3062. // The ``page'' parameter is not used by xterm, and will be omit-
  3063. // ted.
  3064. Program.prototype.decrqlp =
  3065. Program.prototype.req_mouse_pos =
  3066. Program.prototype.reqmp =
  3067. Program.prototype.requestLocatorPosition = function(params, callback) {
  3068. // See also:
  3069. // get_mouse / getm / Gm
  3070. // mouse_info / minfo / Mi
  3071. // Correct for tput?
  3072. if (this.has('req_mouse_pos')) {
  3073. var code = this.tput.req_mouse_pos.apply(this.tput, params);
  3074. return this.response('locator-position', code, callback);
  3075. }
  3076. return this.response('locator-position',
  3077. '\x1b[' + (param || '') + '\'|', callback);
  3078. };
  3079. // CSI P m SP }
  3080. // Insert P s Column(s) (default = 1) (DECIC), VT420 and up.
  3081. // NOTE: xterm doesn't enable this code by default.
  3082. Program.prototype.decic =
  3083. Program.prototype.insertColumns = function() {
  3084. return this._write('\x1b[' + slice.call(arguments).join(';') + ' }');
  3085. };
  3086. // CSI P m SP ~
  3087. // Delete P s Column(s) (default = 1) (DECDC), VT420 and up
  3088. // NOTE: xterm doesn't enable this code by default.
  3089. Program.prototype.decdc =
  3090. Program.prototype.deleteColumns = function() {
  3091. return this._write('\x1b[' + slice.call(arguments).join(';') + ' ~');
  3092. };
  3093. Program.prototype.out = function(name) {
  3094. this.ret = true;
  3095. var out = this[name].apply(this, args);
  3096. this.ret = false;
  3097. return out;
  3098. };
  3099. Program.prototype.sigtstp = function(callback) {
  3100. var resume = this.pause();
  3101. process.once('SIGCONT', function() {
  3102. resume();
  3103. if (callback) callback();
  3104. });
  3105. process.kill(process.pid, 'SIGTSTP');
  3106. };
  3107. Program.prototype.pause = function(callback) {
  3108. var self = this
  3109. , isAlt = this.isAlt
  3110. , mouseEnabled = this.mouseEnabled;
  3111. this.lsaveCursor('pause');
  3112. //this.csr(0, screen.height - 1);
  3113. if (isAlt) this.normalBuffer();
  3114. this.showCursor();
  3115. if (mouseEnabled) this.disableMouse();
  3116. var write = this.output.write;
  3117. this.output.write = function() {};
  3118. this.input.setRawMode(false);
  3119. this.input.pause();
  3120. return this._resume = function() {
  3121. delete self._resume;
  3122. self.input.setRawMode(true);
  3123. self.input.resume();
  3124. self.output.write = write;
  3125. if (isAlt) self.alternateBuffer();
  3126. //self.csr(0, screen.height - 1);
  3127. if (mouseEnabled) self.enableMouse();
  3128. self.lrestoreCursor('pause', true);
  3129. if (callback) callback();
  3130. };
  3131. };
  3132. Program.prototype.resume = function(callback) {
  3133. if (this._resume) return this._resume();
  3134. };
  3135. /**
  3136. * Helpers
  3137. */
  3138. // We could do this easier by just manipulating the _events object, or for
  3139. // older versions of node, manipulating the array returned by listeners(), but
  3140. // neither of these methods are guaranteed to work in future versions of node.
  3141. function unshiftEvent(obj, event, listener) {
  3142. var listeners = obj.listeners(event);
  3143. obj.removeAllListeners(event);
  3144. obj.on(event, listener);
  3145. listeners.forEach(function(listener) {
  3146. obj.on(event, listener);
  3147. });
  3148. };
  3149. function merge(out) {
  3150. slice.call(arguments, 1).forEach(function(obj) {
  3151. Object.keys(obj).forEach(function(key) {
  3152. out[key] = obj[key];
  3153. });
  3154. });
  3155. return out;
  3156. }
  3157. /**
  3158. * Expose
  3159. */
  3160. module.exports = Program;