• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const {
4  NumberIsNaN,
5} = primordials;
6
7const {
8  codes: {
9    ERR_INVALID_ARG_VALUE,
10    ERR_INVALID_CURSOR_POS,
11  },
12} = require('internal/errors');
13
14const {
15  validateFunction,
16} = require('internal/validators');
17const {
18  CSI,
19} = require('internal/readline/utils');
20
21const {
22  kClearLine,
23  kClearScreenDown,
24  kClearToLineBeginning,
25  kClearToLineEnd,
26} = CSI;
27
28
29/**
30 * moves the cursor to the x and y coordinate on the given stream
31 */
32
33function cursorTo(stream, x, y, callback) {
34  if (callback !== undefined) {
35    validateFunction(callback, 'callback');
36  }
37
38  if (typeof y === 'function') {
39    callback = y;
40    y = undefined;
41  }
42
43  if (NumberIsNaN(x)) throw new ERR_INVALID_ARG_VALUE('x', x);
44  if (NumberIsNaN(y)) throw new ERR_INVALID_ARG_VALUE('y', y);
45
46  if (stream == null || (typeof x !== 'number' && typeof y !== 'number')) {
47    if (typeof callback === 'function') process.nextTick(callback, null);
48    return true;
49  }
50
51  if (typeof x !== 'number') throw new ERR_INVALID_CURSOR_POS();
52
53  const data = typeof y !== 'number' ? CSI`${x + 1}G` : CSI`${y + 1};${x + 1}H`;
54  return stream.write(data, callback);
55}
56
57/**
58 * moves the cursor relative to its current location
59 */
60
61function moveCursor(stream, dx, dy, callback) {
62  if (callback !== undefined) {
63    validateFunction(callback, 'callback');
64  }
65
66  if (stream == null || !(dx || dy)) {
67    if (typeof callback === 'function') process.nextTick(callback, null);
68    return true;
69  }
70
71  let data = '';
72
73  if (dx < 0) {
74    data += CSI`${-dx}D`;
75  } else if (dx > 0) {
76    data += CSI`${dx}C`;
77  }
78
79  if (dy < 0) {
80    data += CSI`${-dy}A`;
81  } else if (dy > 0) {
82    data += CSI`${dy}B`;
83  }
84
85  return stream.write(data, callback);
86}
87
88/**
89 * clears the current line the cursor is on:
90 *   -1 for left of the cursor
91 *   +1 for right of the cursor
92 *    0 for the entire line
93 */
94
95function clearLine(stream, dir, callback) {
96  if (callback !== undefined) {
97    validateFunction(callback, 'callback');
98  }
99
100  if (stream === null || stream === undefined) {
101    if (typeof callback === 'function') process.nextTick(callback, null);
102    return true;
103  }
104
105  const type =
106    dir < 0 ? kClearToLineBeginning : dir > 0 ? kClearToLineEnd : kClearLine;
107  return stream.write(type, callback);
108}
109
110/**
111 * clears the screen from the current position of the cursor down
112 */
113
114function clearScreenDown(stream, callback) {
115  if (callback !== undefined) {
116    validateFunction(callback, 'callback');
117  }
118
119  if (stream === null || stream === undefined) {
120    if (typeof callback === 'function') process.nextTick(callback, null);
121    return true;
122  }
123
124  return stream.write(kClearScreenDown, callback);
125}
126
127module.exports = {
128  clearLine,
129  clearScreenDown,
130  cursorTo,
131  moveCursor,
132};
133