pty-shell 1.2.1 → 1.3.0

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.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # pty-shell
2
2
  This is a virtual PTY shell that can be used to filter or log executable commands. It can also be used in a browser environment. Currently, it does not support features like piping. It supports the use of `node-pty`. For more usage examples, you can refer to the code in the [filecat](https://github.com/xiaobaidadada/filecat) project.
3
3
  It needs to be used in combination with projects similar to xterm.js.
4
- 这是一个虚拟的pty shell ,可以用来过滤或者记录可执行命令, 并可以用于浏览器环境, 目前并不支持管道等功能,支持使用 node-pty ,更多使用例子目前可以参考 filecat(https://github.com/xiaobaidadada/filecat)项目中的代码 。
4
+ 这是一个虚拟的pty shell ,可以用来过滤或者记录可执行命令, 只支持node环境,不支持浏览器, 目前并不支持管道等功能,支持使用 node-pty ,更多使用例子目前可以参考 filecat(https://github.com/xiaobaidadada/filecat)项目中的代码 。
5
5
  需要配合 xterm.js 类似的项目组合使用
6
6
  # Sample Example
7
7
  ```js
@@ -0,0 +1,5 @@
1
+ export declare class CharUtil {
2
+ static isFullCharWidth(char: any): boolean;
3
+ static readFullCharIndex(str: string, start_index: number, len: number): number;
4
+ static get_full_char_num(str: string): number;
5
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CharUtil = void 0;
4
+ class CharUtil {
5
+ // 判断一个字符是全角还是半角
6
+ static isFullCharWidth(char) {
7
+ // 计算字符的 UTF-8 编码字节长度
8
+ const byteLength = Buffer.byteLength(char, 'utf8');
9
+ // 如果字符的字节长度大于 1,说明是全角字符
10
+ return byteLength > 1;
11
+ }
12
+ // 从start_index往前多少个位置获取指定数量的 半角 字符(宽字符算两个)
13
+ static readFullCharIndex(str, start_index, len) {
14
+ if (!str)
15
+ return 0;
16
+ if (start_index >= str.length)
17
+ return 0;
18
+ let num = 0;
19
+ let char_num = 0;
20
+ for (let i = start_index; i < str.length; i++) {
21
+ if (this.isFullCharWidth(str[i])) {
22
+ num += 2;
23
+ }
24
+ else {
25
+ num++;
26
+ }
27
+ char_num++;
28
+ if (num >= len)
29
+ return char_num;
30
+ }
31
+ return char_num;
32
+ }
33
+ // 获取字符串中有多少个 字符(将宽字符统计成两个)
34
+ static get_full_char_num(str) {
35
+ if (!str)
36
+ return 0;
37
+ let char_num = 0;
38
+ for (let i = 0; i < str.length; i++) {
39
+ if (this.isFullCharWidth(str[i])) {
40
+ char_num += 2;
41
+ }
42
+ else {
43
+ char_num++;
44
+ }
45
+ }
46
+ return char_num;
47
+ }
48
+ }
49
+ exports.CharUtil = CharUtil;
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  * 读取输出与写入输入:捕获输出并发送输入,模拟用户交互。
9
9
  * 信号和控制字符支持:处理回车、换行等控制字符,并支持信号转发。
10
10
  */
11
+ import { child_func_constructor } from "./type";
11
12
  export declare enum exec_type {
12
13
  not = -1,// 不能执行
13
14
  auto_child_process = 0,// 使用内置子线程执行(除了cd命令)
@@ -32,7 +33,6 @@ interface PtyShellUserMethod {
32
33
  }
33
34
  interface Param extends Partial<PtyShellUserMethod> {
34
35
  cwd: string;
35
- not_use_node_pre_cmd_exec?: boolean;
36
36
  node_pty?: any;
37
37
  cols?: number;
38
38
  rows?: number;
@@ -41,7 +41,7 @@ interface Param extends Partial<PtyShellUserMethod> {
41
41
  history_line?: string[];
42
42
  history_line_max?: number;
43
43
  }
44
- type CmdHandler = (params: string[], send_prompt?: (data: string) => void) => Promise<void>;
44
+ type CmdHandler = (params: string[], send_prompt?: (str: string, send_prompt?: boolean) => void) => Promise<void>;
45
45
  export declare class PtyShell implements PtyShellUserMethod {
46
46
  rows: number;
47
47
  cols: number;
@@ -49,7 +49,7 @@ export declare class PtyShell implements PtyShellUserMethod {
49
49
  env: {};
50
50
  constructor(param: Param);
51
51
  cmd_params_auto_completion(param_str: any): string | undefined;
52
- cmd_exe_auto_completion: any;
52
+ cmd_exe_auto_completion: (str: string) => string;
53
53
  on_prompt_call: (cwd: any) => {
54
54
  str: string;
55
55
  char_num: number;
@@ -63,18 +63,17 @@ export declare class PtyShell implements PtyShellUserMethod {
63
63
  exe_cmd: string;
64
64
  params: string[];
65
65
  }>;
66
- private cmd_set;
67
66
  private shell_set;
68
- private node_require;
69
- private not_use_node_pre_cmd_exec;
70
67
  private cmd_exec_map;
68
+ private js_child_map;
71
69
  private prompt_call_len;
72
70
  private is_running;
73
71
  private child_now_line;
74
72
  private word_detection;
75
73
  private node_pty;
76
74
  private child;
77
- private is_pty;
75
+ private node_pty_child;
76
+ private js_func_child;
78
77
  private line;
79
78
  private line_index;
80
79
  private select_line;
@@ -88,6 +87,7 @@ export declare class PtyShell implements PtyShellUserMethod {
88
87
  */
89
88
  reset_option(param: Param): void;
90
89
  add_cmd_handle(exe_cmd: string, handle: CmdHandler): void;
90
+ add_js_child(name: string, child: child_func_constructor): void;
91
91
  close(): void;
92
92
  kill(): void;
93
93
  /**
@@ -100,12 +100,6 @@ export declare class PtyShell implements PtyShellUserMethod {
100
100
  * @param data
101
101
  */
102
102
  write(data: string): Promise<void>;
103
- /**
104
- * static method
105
- */
106
- static isFullCharWidth(char: any): boolean;
107
- static readFullCharIndex(str: string, start_index: number, len: number): number;
108
- static get_full_char_num(str: string): number;
109
103
  /**
110
104
  * private method
111
105
  */
@@ -116,6 +110,7 @@ export declare class PtyShell implements PtyShellUserMethod {
116
110
  private insert_line;
117
111
  private close_child;
118
112
  private next_not_enter;
113
+ private have_child;
119
114
  private send_and_enter;
120
115
  private update_line;
121
116
  private cancel_selected;
@@ -139,4 +134,7 @@ export declare class PtyShell implements PtyShellUserMethod {
139
134
  private removeCharacterAt;
140
135
  private delete_all_enter;
141
136
  }
142
- export {};
137
+ export * from "./type";
138
+ export * from "./char.util";
139
+ export * from "./path_util";
140
+ export * from "./word_detection_js";
package/dist/index.js CHANGED
@@ -9,6 +9,42 @@
9
9
  * 读取输出与写入输入:捕获输出并发送输入,模拟用户交互。
10
10
  * 信号和控制字符支持:处理回车、换行等控制字符,并支持信号转发。
11
11
  */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
46
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
47
+ };
12
48
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
49
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
50
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -22,6 +58,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
22
58
  exports.PtyShell = exports.exec_cmd_type = exports.exec_type = void 0;
23
59
  const word_detection_js_1 = require("./word_detection_js");
24
60
  const path_util_1 = require("./path_util");
61
+ const char_util_1 = require("./char.util");
62
+ const child_process = __importStar(require("node:child_process"));
63
+ const fs = require("fs");
64
+ const path = require("path");
65
+ // const child_process = require("child_process");
25
66
  // import {SystemUtil} from "../sys/sys.utl";
26
67
  /**
27
68
  * 功能说明:
@@ -32,7 +73,7 @@ const path_util_1 = require("./path_util");
32
73
  * 5. 对于特殊的 shell 命令 会使用 node-pty 来执行 并让shell托管所有的输入输出数据
33
74
  * 6. 使用了shell: true 参数 系统的默认shell可以支持管道等操作,还可以支持程序路劲查找的功能 但是这样无法支持 | 这样左边命令的校验了, todo 暂时取消这个功能。以后再添加 不能使用原生的shell因为不知道会有什么特殊语法从而跳过命令校验
34
75
  */
35
- const cmd_list = ['ls', 'cd', 'pwd']; // 仅支持这三个内置命令 cd 命令是唯一支持参数的
76
+ // const cmd_list = ['ls', 'cd', 'pwd']; // 仅支持这三个内置命令 cd 命令是唯一支持参数的
36
77
  /**
37
78
  * \r 是回车 光标移动到最右边 \n 是换行,当前位置下一行 和\x1b[1B 作用一样
38
79
  * \x1b 是 ESC 后面跟着控制字符
@@ -79,19 +120,16 @@ class PtyShell {
79
120
  this.env = {};
80
121
  this.on_prompt_call = (cwd) => {
81
122
  const str = `${cwd}:# `;
82
- return { str, char_num: PtyShell.get_full_char_num(str) };
123
+ return { str, char_num: char_util_1.CharUtil.get_full_char_num(str) };
83
124
  };
84
125
  this.on_call = (data) => {
85
126
  };
86
127
  this.on_control_cmd = (type, data) => {
87
128
  };
88
- this.cmd_set = new Set(cmd_list);
89
- this.node_require = {};
90
- this.not_use_node_pre_cmd_exec = false;
91
129
  this.cmd_exec_map = new Map();
130
+ this.js_child_map = new Map();
92
131
  this.is_running = true;
93
132
  this.child_now_line = '';
94
- this.is_pty = false;
95
133
  this.line = "";
96
134
  this.line_index = -1; // 当前指针在 某个字符(后面)
97
135
  this.select_line = "";
@@ -102,20 +140,30 @@ class PtyShell {
102
140
  this.history_line_max = 20;
103
141
  this.next_not_enter = false;
104
142
  this.reset_option(param);
105
- if (!this.not_use_node_pre_cmd_exec) {
106
- this.node_require.fs = require("fs");
107
- this.node_require.path = require("path");
108
- this.node_require.child_process = require('child_process');
109
- }
110
143
  this.on_call(this.raw_prompt);
144
+ // 添加自定义处理方法
145
+ this.add_cmd_handle("pwd", (params, send) => __awaiter(this, void 0, void 0, function* () {
146
+ this.send_and_enter(`${this.cwd}`);
147
+ }));
148
+ this.add_cmd_handle("cd", (params, send) => __awaiter(this, void 0, void 0, function* () {
149
+ const p = path.isAbsolute(params[0]) ? params[0] : path.join(this.cwd, params[0]);
150
+ if (!fs.existsSync(p)) {
151
+ this.send_and_enter(`not directory ${p}`);
152
+ }
153
+ this.cwd = p;
154
+ this.send_and_enter(``);
155
+ this.word_detection = undefined; // 清空检测器
156
+ }));
157
+ this.add_cmd_handle("ls", (params, send) => __awaiter(this, void 0, void 0, function* () {
158
+ var _a;
159
+ const items = fs.readdirSync((_a = params === null || params === void 0 ? void 0 : params[0]) !== null && _a !== void 0 ? _a : this.cwd); // 读取目录内容
160
+ const v = this.cols_handle(" " + items.join(" "));
161
+ this.send_and_enter(v);
162
+ }));
111
163
  }
112
164
  // cmd 命令 参数预测 只要是参数都可能是本目录下的文件名所以可以检测一下
113
165
  cmd_params_auto_completion(param_str) {
114
- // 这里的默认实现是开启了使用 node
115
- if (this.not_use_node_pre_cmd_exec) {
116
- return;
117
- }
118
- const items = this.node_require.fs.readdirSync(this.cwd); // 读取目录内容
166
+ const items = fs.readdirSync(this.cwd); // 读取目录内容
119
167
  if (!this.word_detection) {
120
168
  this.word_detection = new word_detection_js_1.word_detection_js();
121
169
  for (const item of items) {
@@ -143,7 +191,9 @@ class PtyShell {
143
191
  }
144
192
  add_cmd_handle(exe_cmd, handle) {
145
193
  this.cmd_exec_map.set(exe_cmd, handle);
146
- this.cmd_set.add(exe_cmd);
194
+ }
195
+ add_js_child(name, child) {
196
+ this.js_child_map.set(name, child);
147
197
  }
148
198
  close() {
149
199
  this.is_running = false;
@@ -162,7 +212,7 @@ class PtyShell {
162
212
  const max_index = str.length - 1;
163
213
  const list = [];
164
214
  let last_index = 0; // 上一次位置
165
- let index = PtyShell.readFullCharIndex(str, 0, this.cols);
215
+ let index = char_util_1.CharUtil.readFullCharIndex(str, 0, this.cols);
166
216
  let count = 0;
167
217
  while (index < max_index) {
168
218
  if (count > max_index)
@@ -174,21 +224,21 @@ class PtyShell {
174
224
  if (this.is_empty(str[f])) {
175
225
  list.push(str.substring(last_index, f + 1));
176
226
  last_index = f + 1;
177
- index = f + 1 + PtyShell.readFullCharIndex(str, f + 1, this.cols);
227
+ index = f + 1 + char_util_1.CharUtil.readFullCharIndex(str, f + 1, this.cols);
178
228
  continue;
179
229
  }
180
230
  if (f === last_index) {
181
231
  // 最后一位 直接把本行全部添加进去
182
232
  list.push(str.substring(last_index, index));
183
233
  last_index = index;
184
- index = index + PtyShell.readFullCharIndex(str, index, this.cols);
234
+ index = index + char_util_1.CharUtil.readFullCharIndex(str, index, this.cols);
185
235
  }
186
236
  }
187
237
  }
188
238
  else {
189
239
  list.push(str.substring(last_index, index));
190
240
  last_index = index;
191
- index = index + PtyShell.readFullCharIndex(str, index + 1, this.cols);
241
+ index = index + char_util_1.CharUtil.readFullCharIndex(str, index + 1, this.cols);
192
242
  }
193
243
  }
194
244
  if (index >= max_index) {
@@ -202,7 +252,7 @@ class PtyShell {
202
252
  */
203
253
  write(data) {
204
254
  return __awaiter(this, void 0, void 0, function* () {
205
- if (this.child && this.is_pty) {
255
+ if (this.have_child()) {
206
256
  // 终端shell 完全 托管给 别的程序
207
257
  this.spawn_write(data);
208
258
  return;
@@ -252,52 +302,6 @@ class PtyShell {
252
302
  }
253
303
  });
254
304
  }
255
- /**
256
- * static method
257
- */
258
- // 判断一个字符是全角还是半角
259
- static isFullCharWidth(char) {
260
- // 计算字符的 UTF-8 编码字节长度
261
- const byteLength = Buffer.byteLength(char, 'utf8');
262
- // 如果字符的字节长度大于 1,说明是全角字符
263
- return byteLength > 1;
264
- }
265
- // 从start_index往前多少个位置获取指定数量的 半角 字符(宽字符算两个)
266
- static readFullCharIndex(str, start_index, len) {
267
- if (!str)
268
- return 0;
269
- if (start_index >= str.length)
270
- return 0;
271
- let num = 0;
272
- let char_num = 0;
273
- for (let i = start_index; i < str.length; i++) {
274
- if (this.isFullCharWidth(str[i])) {
275
- num += 2;
276
- }
277
- else {
278
- num++;
279
- }
280
- char_num++;
281
- if (num >= len)
282
- return char_num;
283
- }
284
- return char_num;
285
- }
286
- // 获取字符串中有多少个 字符(将宽字符统计成两个)
287
- static get_full_char_num(str) {
288
- if (!str)
289
- return 0;
290
- let char_num = 0;
291
- for (let i = 0; i < str.length; i++) {
292
- if (this.isFullCharWidth(str[i])) {
293
- char_num += 2;
294
- }
295
- else {
296
- char_num++;
297
- }
298
- }
299
- return char_num;
300
- }
301
305
  /**
302
306
  * private method
303
307
  */
@@ -332,17 +336,29 @@ class PtyShell {
332
336
  }
333
337
  close_child(code) {
334
338
  this.child_now_line = '';
335
- if (this.child) {
339
+ let child = this.child;
340
+ if (this.node_pty_child) {
341
+ child = this.node_pty_child;
342
+ }
343
+ if (child) {
336
344
  // SystemUtil.killProcess(this.child.pid);
337
- const pid = this.child.pid;
345
+ const pid = child.pid;
338
346
  if (this.on_child_kill) {
339
347
  this.exec_end_call(code, pid);
340
348
  }
341
349
  else {
342
- this.child.kill(); // 不同平台信号不同 win 默认 SIGHUP
350
+ child.kill(); // 不同平台信号不同 win 默认 SIGHUP
343
351
  }
344
- this.child = undefined;
345
352
  }
353
+ if (this.js_func_child) {
354
+ this.js_func_child.kill();
355
+ }
356
+ this.child = undefined;
357
+ this.node_pty_child = null;
358
+ this.js_func_child = null;
359
+ }
360
+ have_child() {
361
+ return this.child != null || this.node_pty_child != null || this.js_func_child != null;
346
362
  }
347
363
  send_and_enter(str, send_prompt = false) {
348
364
  try {
@@ -365,7 +381,7 @@ class PtyShell {
365
381
  }
366
382
  if (i === 0 || i !== last_i)
367
383
  list.push(str.substring(i));
368
- if (this.child) {
384
+ if (this.have_child()) {
369
385
  // 添加子进程的提示换行
370
386
  this.child_now_line = list[list.length - 1];
371
387
  }
@@ -380,7 +396,7 @@ class PtyShell {
380
396
  }
381
397
  this.next_not_enter = str.endsWith('\n\r') || str.endsWith('\r\n'); // 下一次不用换行了
382
398
  }
383
- if (!this.child || send_prompt) {
399
+ if (!this.have_child() || send_prompt) {
384
400
  this.on_call(`${this.enter_prompt}`);
385
401
  }
386
402
  this.clear_line();
@@ -393,7 +409,7 @@ class PtyShell {
393
409
  update_line(param) {
394
410
  var _a, _b;
395
411
  const prompt = !this.child ? this.raw_prompt : this.child_now_line;
396
- let len = (!this.child ? this.prompt_call_len : PtyShell.get_full_char_num(prompt)) + this.line_char_index; // 字符串前面的字符数量
412
+ let len = (!this.child ? this.prompt_call_len : char_util_1.CharUtil.get_full_char_num(prompt)) + this.line_char_index; // 字符串前面的字符数量
397
413
  if (param && param.line_add_num) {
398
414
  len += param.line_add_num;
399
415
  }
@@ -421,7 +437,7 @@ class PtyShell {
421
437
  get line_char_index() {
422
438
  if (this.line_index === -1)
423
439
  return 0;
424
- return PtyShell.get_full_char_num(this.line.substring(0, this.line_index + 1));
440
+ return char_util_1.CharUtil.get_full_char_num(this.line.substring(0, this.line_index + 1));
425
441
  }
426
442
  ctrl_exec(str) {
427
443
  let cancel_selected = true; // 取消选中
@@ -483,7 +499,7 @@ class PtyShell {
483
499
  break;
484
500
  }
485
501
  this.line_index++;
486
- const len = PtyShell.get_full_char_num(this.line[this.line_index]);
502
+ const len = char_util_1.CharUtil.get_full_char_num(this.line[this.line_index]);
487
503
  if (this.select_line) {
488
504
  this.update_line({ line_add_num: 1 });
489
505
  break;
@@ -497,7 +513,7 @@ class PtyShell {
497
513
  if (this.line_index === -1) {
498
514
  break;
499
515
  }
500
- const len = PtyShell.get_full_char_num(this.line[this.line_index]);
516
+ const len = char_util_1.CharUtil.get_full_char_num(this.line[this.line_index]);
501
517
  this.line_index--;
502
518
  if (this.select_line) {
503
519
  this.update_line({ line_add_num: 1 });
@@ -726,23 +742,12 @@ class PtyShell {
726
742
  parse_exec() {
727
743
  return __awaiter(this, void 0, void 0, function* () {
728
744
  // const line = this.delete_all_enter(this.line);
729
- if (!this.line && !this.child) {
745
+ if (!this.line && !this.have_child()) {
730
746
  this.send_and_enter("");
731
747
  this.clear_line();
732
748
  return;
733
749
  }
734
750
  this.push_history_line(this.line);
735
- if (this.child && this.is_pty) {
736
- // 终端shell 完全 托管给 别的程序
737
- this.spawn_write(`${this.line}\r`);
738
- return;
739
- }
740
- else if (this.child) {
741
- // 把数据给正在运行的别的程序
742
- this.spawn_write(`${this.line}\n`);
743
- this.clear_line();
744
- return;
745
- }
746
751
  let { exe, params } = this.get_exec(this.line);
747
752
  this.history_line_index = -1;
748
753
  try {
@@ -772,12 +777,24 @@ class PtyShell {
772
777
  exe = r.exe_cmd;
773
778
  params = r.params;
774
779
  }
775
- if (this.cmd_set.has(exe)) {
780
+ if (this.cmd_exec_map.has(exe)) {
776
781
  // 检测某个已经有预处理的命令 包括用户自定义的
777
782
  yield this.exec_cmd(exe, params);
778
783
  // 不用再继续了
779
784
  this.clear_line();
780
785
  this.exec_end_call(0);
786
+ return;
787
+ }
788
+ if (this.js_child_map.has(exe)) {
789
+ const c_ = this.js_child_map.get(exe);
790
+ this.js_func_child = new c_(() => {
791
+ this.send_and_enter("");
792
+ this.next_not_enter = false; // 下一次的换行输出 上一次没有换行
793
+ this.close_child();
794
+ }, (str) => {
795
+ this.on_call(str);
796
+ }, params);
797
+ return;
781
798
  }
782
799
  this.spawn(exe, params, use_noe_pty);
783
800
  this.clear_line();
@@ -812,18 +829,22 @@ class PtyShell {
812
829
  });
813
830
  }
814
831
  spawn_write(str) {
815
- if (this.is_pty) {
816
- this.child.write(str);
832
+ if (this.node_pty_child) {
833
+ this.node_pty_child.write(str);
834
+ // this.child.write(str);
817
835
  }
818
- else {
836
+ else if (this.child) {
819
837
  this.child.stdin.write(str);
820
838
  }
821
- }
822
- spawn(exe, params, use_noe_pty = true, spawn_option) {
823
- if (this.not_use_node_pre_cmd_exec) {
824
- this.send_and_enter(`not_use_node_pre_cmd_exec is true`);
825
- return;
839
+ else if (this.js_func_child) {
840
+ this.js_func_child.write(str);
826
841
  }
842
+ }
843
+ spawn(exe, params, use_noe_pty = true) {
844
+ // if (this.not_use_node_pre_cmd_exec) {
845
+ // this.send_and_enter(`not_use_node_pre_cmd_exec is true`);
846
+ // return;
847
+ // }
827
848
  // this.send_and_enter(""); //
828
849
  // if (!this.child) {
829
850
  // this.on_call(`\n\r`); // 先换个行
@@ -833,30 +854,40 @@ class PtyShell {
833
854
  // exe += '.exe';
834
855
  // }
835
856
  this.on_call(`\n\r`); // 先换个行
836
- this.child = this.node_pty.spawn(exe, params, Object.assign({ name: 'xterm-color', cols: this.cols, rows: this.rows, cwd: this.cwd, useConptyDll: false, useConpty: process.env.NODE_ENV !== "production" ? false : undefined, env: Object.assign(Object.assign({}, process.env), this.env) }, spawn_option));
837
- this.child.onData((data) => {
857
+ this.node_pty_child = this.node_pty.spawn(exe, params, {
858
+ name: 'xterm-color',
859
+ cols: this.cols,
860
+ rows: this.rows,
861
+ cwd: this.cwd, // 设置子进程的工作目录
862
+ useConptyDll: false,
863
+ useConpty: process.env.NODE_ENV !== "production" ? false : undefined, // conpty 可以支持 bash 等命令 从 Windows 10 版本 1809 开始提供 , 但是如果使用了 powershell 这个也就没有必要了,而且设置为false才能使用debug模式运行
864
+ env: Object.assign(Object.assign({}, process.env), this.env), // 传递环境变量
865
+ });
866
+ this.node_pty_child.onData((data) => {
838
867
  this.on_call(data.toString());
839
868
  if (this.on_call_child_raw) {
840
869
  this.on_call_child_raw(data);
841
870
  }
842
871
  });
843
- this.child.onExit(({ exitCode, signal }) => {
872
+ this.node_pty_child.onExit(({ exitCode, signal }) => {
844
873
  this.close_child(exitCode);
845
874
  this.send_and_enter("");
846
875
  // this.send_and_enter(`pty with ${exitCode}`);
847
876
  this.next_not_enter = false; // 下一次的换行输出 上一次没有换行
848
877
  });
849
- this.is_pty = true;
878
+ // this.is_pty = true;
850
879
  }
851
880
  else {
852
- this.is_pty = false;
881
+ // this.is_pty = false;
853
882
  // 其他的没有必要再创建一个 tty 都是资源消耗
854
- this.child = this.node_require.child_process.spawn(exe, params, Object.assign({
883
+ this.child = child_process.spawn(exe, params, {
855
884
  // shell:getShell(),
856
- cwd: this.cwd, env: Object.assign(Object.assign(Object.assign({}, process.env), this.env), { LANG: 'en_US.UTF-8' }),
885
+ cwd: this.cwd, // 设置子进程的工作目录
886
+ env: Object.assign(Object.assign(Object.assign({}, process.env), this.env), { LANG: 'en_US.UTF-8' }), // 传递环境变量
857
887
  // stdio: 'inherit' // 让子进程的输入输出与父进程共享 pipe ignore inherit
858
888
  // timeout: 5000, // 设置超时为 5 秒
859
- maxBuffer: 1024 * 1024 * 10 }, spawn_option));
889
+ // maxBuffer: 1024 * 1024 * 10// 设置缓冲区为 10 MB
890
+ });
860
891
  // 设置编码为 'utf8',确保输出按 UTF-8 编码解析
861
892
  this.child.stdout.setEncoding('utf8');
862
893
  this.child.stdout.on('data', (data) => {
@@ -892,58 +923,20 @@ class PtyShell {
892
923
  }
893
924
  exec_cmd(exe, params) {
894
925
  return __awaiter(this, void 0, void 0, function* () {
926
+ var _a;
895
927
  try {
896
928
  const handle = this.cmd_exec_map.get(exe);
897
- if (exe !== 'cd' && handle) {
898
- // 如果用户有了就用用户的 不用系统自己的 但是 cd 命令排除在外
899
- yield handle(params, (data) => {
900
- this.send_and_enter(data, true);
929
+ if (handle) {
930
+ // 如果用户有了就用用户的 不用系统自己的
931
+ yield handle(params, (data, enter) => {
932
+ this.send_and_enter(data, enter);
901
933
  });
902
934
  return true;
903
935
  }
904
- switch (exe) {
905
- case 'pwd':
906
- {
907
- this.send_and_enter(`${this.cwd}`);
908
- }
909
- return true;
910
- case 'cd':
911
- {
912
- let p;
913
- if (!this.not_use_node_pre_cmd_exec) {
914
- // 有node环境可以检测一下
915
- p = this.node_require.path.isAbsolute(params[0]) ? params[0] : this.node_require.path.join(this.cwd, params[0]);
916
- if (!this.node_require.fs.existsSync(p)) {
917
- this.send_and_enter(`not directory ${p}`);
918
- }
919
- }
920
- else {
921
- // 没有node环境只能这样了 todo 对于 .. 路径有问题
922
- p = (0, path_util_1.path_join)(this.cwd, params[0]);
923
- }
924
- this.cwd = p;
925
- this.send_and_enter(``);
926
- this.word_detection = undefined; // 清空检测器
927
- }
928
- return true;
929
- case 'ls':
930
- {
931
- if (this.not_use_node_pre_cmd_exec) {
932
- return false; // 让其它方式处理
933
- }
934
- const items = this.node_require.fs.readdirSync(this.cwd); // 读取目录内容
935
- const v = this.cols_handle(" " + items.join(" "));
936
- this.send_and_enter(v);
937
- }
938
- return true;
939
- default:
940
- return false; // 让其它方式处理
941
- }
942
936
  }
943
937
  catch (e) {
944
- this.send_and_enter(JSON.stringify(e));
938
+ this.send_and_enter((_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e);
945
939
  }
946
- return false; // 让其它方式处理
947
940
  });
948
941
  }
949
942
  // 解析命令与参数
@@ -1061,3 +1054,7 @@ class PtyShell {
1061
1054
  }
1062
1055
  }
1063
1056
  exports.PtyShell = PtyShell;
1057
+ __exportStar(require("./type"), exports);
1058
+ __exportStar(require("./char.util"), exports);
1059
+ __exportStar(require("./path_util"), exports);
1060
+ __exportStar(require("./word_detection_js"), exports);
package/dist/type.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export interface child_func_type {
2
+ write(str: string): void;
3
+ kill(): void;
4
+ }
5
+ export type child_func_constructor = new (exit_on: () => void, send: (str: string) => void, params: string[]) => child_func_type;
package/dist/type.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pty-shell",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "a virtual PTY shell for javaScript",
5
5
  "author": "xiaobaidadada",
6
6
  "main": "dist/index.js",