@gjsify/tty 0.3.12 → 0.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/esm/index.js +223 -231
  2. package/package.json +6 -6
package/lib/esm/index.js CHANGED
@@ -1,236 +1,228 @@
1
- import { Writable, Readable } from "node:stream";
1
+ import { Readable, Writable } from "node:stream";
2
2
  import GLib from "@girs/glib-2.0";
3
3
  import { nativeTerminal } from "@gjsify/terminal-native";
4
- class ReadStream extends Readable {
5
- isRaw = false;
6
- fd;
7
- constructor(fd = 0) {
8
- super();
9
- this.fd = fd;
10
- }
11
- get isTTY() {
12
- return isatty(this.fd);
13
- }
14
- setRawMode(mode) {
15
- if (nativeTerminal) {
16
- nativeTerminal.Terminal.set_raw_mode(this.fd, mode);
17
- }
18
- if (this.isRaw !== mode) {
19
- this.isRaw = mode;
20
- this.emit("modeChange");
21
- }
22
- return this;
23
- }
24
- }
25
- class WriteStream extends Writable {
26
- isRaw = false;
27
- fd;
28
- _print = console.log;
29
- // Mutable backing fields — updated by _detectSize() and _changeColumns/Rows.
30
- _columns = 80;
31
- _rows = 24;
32
- constructor(fd) {
33
- super();
34
- this.fd = fd;
35
- this._detectSize();
36
- }
37
- get isTTY() {
38
- return isatty(this.fd);
39
- }
40
- get columns() {
41
- if (nativeTerminal) {
42
- const [ok, , cols] = nativeTerminal.Terminal.get_size(this.fd);
43
- if (ok && cols > 0) return cols;
44
- }
45
- return this._columns;
46
- }
47
- set columns(v) {
48
- this._columns = v;
49
- }
50
- get rows() {
51
- if (nativeTerminal) {
52
- const [ok, rows] = nativeTerminal.Terminal.get_size(this.fd);
53
- if (ok && rows > 0) return rows;
54
- }
55
- return this._rows;
56
- }
57
- set rows(v) {
58
- this._rows = v;
59
- }
60
- /** Detect terminal size from environment or native ioctl. */
61
- _detectSize() {
62
- if (nativeTerminal) {
63
- const [ok, rows2, cols2] = nativeTerminal.Terminal.get_size(this.fd);
64
- if (ok && cols2 > 0) {
65
- this._columns = cols2;
66
- this._rows = rows2;
67
- return;
68
- }
69
- }
70
- const cols = parseInt(
71
- globalThis.process?.env?.COLUMNS || (typeof GLib !== "undefined" ? GLib.getenv("COLUMNS") : "") || "0",
72
- 10
73
- );
74
- const rows = parseInt(
75
- globalThis.process?.env?.LINES || (typeof GLib !== "undefined" ? GLib.getenv("LINES") : "") || "0",
76
- 10
77
- );
78
- if (cols > 0) this._columns = cols;
79
- if (rows > 0) this._rows = rows;
80
- }
81
- /**
82
- * Clear the current line.
83
- * dir: -1 = left of cursor, 0 = entire line, 1 = right of cursor
84
- */
85
- clearLine(dir, callback) {
86
- let seq;
87
- if (dir === -1) {
88
- seq = "\x1B[1K";
89
- } else if (dir === 1) {
90
- seq = "\x1B[0K";
91
- } else {
92
- seq = "\x1B[2K";
93
- }
94
- return this.write(seq, callback);
95
- }
96
- /** Clear the screen from the cursor down. */
97
- clearScreenDown(callback) {
98
- return this.write("\x1B[0J", callback);
99
- }
100
- /**
101
- * Move cursor to absolute position (x, y).
102
- * If y is omitted, only move horizontally.
103
- */
104
- cursorTo(x, y, callback) {
105
- if (typeof y === "function") {
106
- callback = y;
107
- y = void 0;
108
- }
109
- let seq;
110
- if (y == null) {
111
- seq = `\x1B[${x + 1}G`;
112
- } else {
113
- seq = `\x1B[${y + 1};${x + 1}H`;
114
- }
115
- return this.write(seq, callback);
116
- }
117
- /**
118
- * Move cursor relative to its current position.
119
- */
120
- moveCursor(dx, dy, callback) {
121
- let seq = "";
122
- if (dx > 0) seq += `\x1B[${dx}C`;
123
- else if (dx < 0) seq += `\x1B[${-dx}D`;
124
- if (dy > 0) seq += `\x1B[${dy}B`;
125
- else if (dy < 0) seq += `\x1B[${-dy}A`;
126
- if (seq.length === 0) {
127
- if (callback) callback();
128
- return true;
129
- }
130
- return this.write(seq, callback);
131
- }
132
- /**
133
- * Get the color depth of the terminal.
134
- * Returns 1 (no color), 4 (16 colors), 8 (256 colors), or 24 (true color).
135
- */
136
- getColorDepth(env) {
137
- const e = env || globalThis.process?.env || {};
138
- if ("FORCE_COLOR" in e) {
139
- const force = e.FORCE_COLOR;
140
- if (force === "0" || force === "false") return 1;
141
- if (force === "1") return 4;
142
- if (force === "2") return 8;
143
- if (force === "3") return 24;
144
- return 4;
145
- }
146
- if ("NO_COLOR" in e) return 1;
147
- const term = e.TERM || "";
148
- const colorterm = e.COLORTERM || "";
149
- if (colorterm === "truecolor" || colorterm === "24bit") return 24;
150
- if (term === "xterm-256color" || term.endsWith("-256color")) return 8;
151
- if (colorterm) return 4;
152
- if (term === "dumb") return 1;
153
- if (term.startsWith("xterm") || term.startsWith("screen") || term.startsWith("vt100") || term.startsWith("linux")) return 4;
154
- return 1;
155
- }
156
- /** Get the terminal window size as [columns, rows]. */
157
- getWindowSize() {
158
- return [this.columns, this.rows];
159
- }
160
- /**
161
- * Check if the terminal supports the given number of colors.
162
- */
163
- hasColors(count, env) {
164
- let _count;
165
- let _env;
166
- if (typeof count === "object") {
167
- _env = count;
168
- _count = 16;
169
- } else {
170
- _count = count ?? 16;
171
- _env = env;
172
- }
173
- const depth = this.getColorDepth(_env);
174
- switch (depth) {
175
- case 1:
176
- return _count >= 2;
177
- case 4:
178
- return _count >= 16;
179
- case 8:
180
- return _count >= 256;
181
- case 24:
182
- return _count >= 16777216;
183
- default:
184
- return false;
185
- }
186
- }
187
- setRawMode(mode) {
188
- if (nativeTerminal) {
189
- nativeTerminal.Terminal.set_raw_mode(this.fd, mode);
190
- }
191
- if (this.isRaw !== mode) {
192
- this.isRaw = mode;
193
- this.emit("modeChange");
194
- }
195
- return this;
196
- }
197
- _write(chunk, enc, cb) {
198
- this._print(enc === "buffer" ? chunk.toString("utf-8") : chunk);
199
- cb(null);
200
- }
201
- _changeColumns(columns) {
202
- if (columns !== this._columns) {
203
- this._columns = columns;
204
- this.emit("resize");
205
- }
206
- }
207
- _changeRows(rows) {
208
- if (rows !== this._rows) {
209
- this._rows = rows;
210
- this.emit("resize");
211
- }
212
- }
213
- }
4
+
5
+ //#region src/index.ts
6
+ var ReadStream = class extends Readable {
7
+ isRaw = false;
8
+ fd;
9
+ constructor(fd = 0) {
10
+ super();
11
+ this.fd = fd;
12
+ }
13
+ get isTTY() {
14
+ return isatty(this.fd);
15
+ }
16
+ setRawMode(mode) {
17
+ if (nativeTerminal) {
18
+ nativeTerminal.Terminal.set_raw_mode(this.fd, mode);
19
+ }
20
+ if (this.isRaw !== mode) {
21
+ this.isRaw = mode;
22
+ this.emit("modeChange");
23
+ }
24
+ return this;
25
+ }
26
+ };
27
+ var WriteStream = class extends Writable {
28
+ isRaw = false;
29
+ fd;
30
+ _print = console.log;
31
+ _columns = 80;
32
+ _rows = 24;
33
+ constructor(fd) {
34
+ super();
35
+ this.fd = fd;
36
+ this._detectSize();
37
+ }
38
+ get isTTY() {
39
+ return isatty(this.fd);
40
+ }
41
+ get columns() {
42
+ if (nativeTerminal) {
43
+ const [ok, , cols] = nativeTerminal.Terminal.get_size(this.fd);
44
+ if (ok && cols > 0) return cols;
45
+ }
46
+ return this._columns;
47
+ }
48
+ set columns(v) {
49
+ this._columns = v;
50
+ }
51
+ get rows() {
52
+ if (nativeTerminal) {
53
+ const [ok, rows] = nativeTerminal.Terminal.get_size(this.fd);
54
+ if (ok && rows > 0) return rows;
55
+ }
56
+ return this._rows;
57
+ }
58
+ set rows(v) {
59
+ this._rows = v;
60
+ }
61
+ /** Detect terminal size from environment or native ioctl. */
62
+ _detectSize() {
63
+ if (nativeTerminal) {
64
+ const [ok, rows, cols] = nativeTerminal.Terminal.get_size(this.fd);
65
+ if (ok && cols > 0) {
66
+ this._columns = cols;
67
+ this._rows = rows;
68
+ return;
69
+ }
70
+ }
71
+ const cols = parseInt(globalThis.process?.env?.COLUMNS || (typeof GLib !== "undefined" ? GLib.getenv("COLUMNS") : "") || "0", 10);
72
+ const rows = parseInt(globalThis.process?.env?.LINES || (typeof GLib !== "undefined" ? GLib.getenv("LINES") : "") || "0", 10);
73
+ if (cols > 0) this._columns = cols;
74
+ if (rows > 0) this._rows = rows;
75
+ }
76
+ /**
77
+ * Clear the current line.
78
+ * dir: -1 = left of cursor, 0 = entire line, 1 = right of cursor
79
+ */
80
+ clearLine(dir, callback) {
81
+ let seq;
82
+ if (dir === -1) {
83
+ seq = "\x1B[1K";
84
+ } else if (dir === 1) {
85
+ seq = "\x1B[0K";
86
+ } else {
87
+ seq = "\x1B[2K";
88
+ }
89
+ return this.write(seq, callback);
90
+ }
91
+ /** Clear the screen from the cursor down. */
92
+ clearScreenDown(callback) {
93
+ return this.write("\x1B[0J", callback);
94
+ }
95
+ /**
96
+ * Move cursor to absolute position (x, y).
97
+ * If y is omitted, only move horizontally.
98
+ */
99
+ cursorTo(x, y, callback) {
100
+ if (typeof y === "function") {
101
+ callback = y;
102
+ y = undefined;
103
+ }
104
+ let seq;
105
+ if (y == null) {
106
+ seq = `\x1b[${x + 1}G`;
107
+ } else {
108
+ seq = `\x1b[${y + 1};${x + 1}H`;
109
+ }
110
+ return this.write(seq, callback);
111
+ }
112
+ /**
113
+ * Move cursor relative to its current position.
114
+ */
115
+ moveCursor(dx, dy, callback) {
116
+ let seq = "";
117
+ if (dx > 0) seq += `\x1b[${dx}C`;
118
+ else if (dx < 0) seq += `\x1b[${-dx}D`;
119
+ if (dy > 0) seq += `\x1b[${dy}B`;
120
+ else if (dy < 0) seq += `\x1b[${-dy}A`;
121
+ if (seq.length === 0) {
122
+ if (callback) callback();
123
+ return true;
124
+ }
125
+ return this.write(seq, callback);
126
+ }
127
+ /**
128
+ * Get the color depth of the terminal.
129
+ * Returns 1 (no color), 4 (16 colors), 8 (256 colors), or 24 (true color).
130
+ */
131
+ getColorDepth(env) {
132
+ const e = env || globalThis.process?.env || {};
133
+ if ("FORCE_COLOR" in e) {
134
+ const force = e.FORCE_COLOR;
135
+ if (force === "0" || force === "false") return 1;
136
+ if (force === "1") return 4;
137
+ if (force === "2") return 8;
138
+ if (force === "3") return 24;
139
+ return 4;
140
+ }
141
+ if ("NO_COLOR" in e) return 1;
142
+ const term = e.TERM || "";
143
+ const colorterm = e.COLORTERM || "";
144
+ if (colorterm === "truecolor" || colorterm === "24bit") return 24;
145
+ if (term === "xterm-256color" || term.endsWith("-256color")) return 8;
146
+ if (colorterm) return 4;
147
+ if (term === "dumb") return 1;
148
+ if (term.startsWith("xterm") || term.startsWith("screen") || term.startsWith("vt100") || term.startsWith("linux")) return 4;
149
+ return 1;
150
+ }
151
+ /** Get the terminal window size as [columns, rows]. */
152
+ getWindowSize() {
153
+ return [this.columns, this.rows];
154
+ }
155
+ /**
156
+ * Check if the terminal supports the given number of colors.
157
+ */
158
+ hasColors(count, env) {
159
+ let _count;
160
+ let _env;
161
+ if (typeof count === "object") {
162
+ _env = count;
163
+ _count = 16;
164
+ } else {
165
+ _count = count ?? 16;
166
+ _env = env;
167
+ }
168
+ const depth = this.getColorDepth(_env);
169
+ switch (depth) {
170
+ case 1: return _count >= 2;
171
+ case 4: return _count >= 16;
172
+ case 8: return _count >= 256;
173
+ case 24: return _count >= 16777216;
174
+ default: return false;
175
+ }
176
+ }
177
+ setRawMode(mode) {
178
+ if (nativeTerminal) {
179
+ nativeTerminal.Terminal.set_raw_mode(this.fd, mode);
180
+ }
181
+ if (this.isRaw !== mode) {
182
+ this.isRaw = mode;
183
+ this.emit("modeChange");
184
+ }
185
+ return this;
186
+ }
187
+ _write(chunk, enc, cb) {
188
+ this._print(enc === "buffer" ? chunk.toString("utf-8") : chunk);
189
+ cb(null);
190
+ }
191
+ _changeColumns(columns) {
192
+ if (columns !== this._columns) {
193
+ this._columns = columns;
194
+ this.emit("resize");
195
+ }
196
+ }
197
+ _changeRows(rows) {
198
+ if (rows !== this._rows) {
199
+ this._rows = rows;
200
+ this.emit("resize");
201
+ }
202
+ }
203
+ };
204
+ /**
205
+ * Check if a file descriptor refers to a TTY.
206
+ * Uses Posix.isatty() when @gjsify/terminal-native is installed (accurate).
207
+ * Falls back to GLib.log_writer_supports_color() as a reliable TTY proxy.
208
+ */
214
209
  function isatty(fd) {
215
- if (fd instanceof ReadStream || fd instanceof WriteStream) {
216
- return isatty(fd.fd);
217
- }
218
- if (typeof fd === "number") {
219
- if (nativeTerminal) {
220
- return nativeTerminal.Terminal.is_tty(fd);
221
- }
222
- return GLib.log_writer_supports_color(fd);
223
- }
224
- return false;
210
+ if (fd instanceof ReadStream || fd instanceof WriteStream) {
211
+ return isatty(fd.fd);
212
+ }
213
+ if (typeof fd === "number") {
214
+ if (nativeTerminal) {
215
+ return nativeTerminal.Terminal.is_tty(fd);
216
+ }
217
+ return GLib.log_writer_supports_color(fd);
218
+ }
219
+ return false;
225
220
  }
226
- var index_default = {
227
- isatty,
228
- WriteStream,
229
- ReadStream
230
- };
231
- export {
232
- ReadStream,
233
- WriteStream,
234
- index_default as default,
235
- isatty
221
+ var src_default = {
222
+ isatty,
223
+ WriteStream,
224
+ ReadStream
236
225
  };
226
+
227
+ //#endregion
228
+ export { ReadStream, WriteStream, src_default as default, isatty };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/tty",
3
- "version": "0.3.12",
3
+ "version": "0.3.14",
4
4
  "description": "Node.js tty module for Gjs",
5
5
  "module": "lib/esm/index.js",
6
6
  "types": "lib/types/index.d.ts",
@@ -30,14 +30,14 @@
30
30
  "tty"
31
31
  ],
32
32
  "devDependencies": {
33
- "@gjsify/cli": "^0.3.12",
34
- "@gjsify/unit": "^0.3.12",
33
+ "@gjsify/cli": "^0.3.14",
34
+ "@gjsify/unit": "^0.3.14",
35
35
  "@types/node": "^25.6.0",
36
36
  "typescript": "^6.0.3"
37
37
  },
38
38
  "dependencies": {
39
- "@girs/glib-2.0": "^2.88.0-4.0.0-rc.9",
40
- "@gjsify/stream": "^0.3.12",
41
- "@gjsify/terminal-native": "^0.3.12"
39
+ "@girs/glib-2.0": "2.88.0-4.0.0-rc.9",
40
+ "@gjsify/stream": "^0.3.14",
41
+ "@gjsify/terminal-native": "^0.3.14"
42
42
  }
43
43
  }