pty-shell 1.2.2 → 1.4.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;
@@ -83,11 +82,15 @@ export declare class PtyShell implements PtyShellUserMethod {
83
82
  private history_line;
84
83
  private history_line_index;
85
84
  private history_line_max;
85
+ private _not_write;
86
+ get not_write(): boolean;
87
+ set not_write(value: boolean);
86
88
  /**
87
89
  * public method
88
90
  */
89
91
  reset_option(param: Param): void;
90
92
  add_cmd_handle(exe_cmd: string, handle: CmdHandler): void;
93
+ add_js_child(name: string, child: child_func_constructor): void;
91
94
  close(): void;
92
95
  kill(): void;
93
96
  /**
@@ -100,12 +103,6 @@ export declare class PtyShell implements PtyShellUserMethod {
100
103
  * @param data
101
104
  */
102
105
  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
106
  /**
110
107
  * private method
111
108
  */
@@ -116,6 +113,7 @@ export declare class PtyShell implements PtyShellUserMethod {
116
113
  private insert_line;
117
114
  private close_child;
118
115
  private next_not_enter;
116
+ private have_child;
119
117
  private send_and_enter;
120
118
  private update_line;
121
119
  private cancel_selected;
@@ -139,4 +137,7 @@ export declare class PtyShell implements PtyShellUserMethod {
139
137
  private removeCharacterAt;
140
138
  private delete_all_enter;
141
139
  }
142
- export {};
140
+ export * from "./type";
141
+ export * from "./char.util";
142
+ export * from "./path_util";
143
+ 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 = "";
@@ -100,22 +138,34 @@ class PtyShell {
100
138
  this.history_line = [];
101
139
  this.history_line_index = -1;
102
140
  this.history_line_max = 20;
141
+ this._not_write = false;
103
142
  this.next_not_enter = false;
104
143
  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
144
  this.on_call(this.raw_prompt);
145
+ // 添加自定义处理方法
146
+ this.add_cmd_handle("pwd", (params, send) => __awaiter(this, void 0, void 0, function* () {
147
+ this.send_and_enter(`${this.cwd}`);
148
+ }));
149
+ this.add_cmd_handle("cd", (params, send) => __awaiter(this, void 0, void 0, function* () {
150
+ const p = path.isAbsolute(params[0]) ? params[0] : path.join(this.cwd, params[0]);
151
+ if (!fs.existsSync(p)) {
152
+ this.send_and_enter(`not directory ${p}`);
153
+ return;
154
+ }
155
+ this.cwd = p;
156
+ this.send_and_enter(``);
157
+ this.word_detection = undefined; // 清空检测器
158
+ }));
159
+ this.add_cmd_handle("ls", (params, send) => __awaiter(this, void 0, void 0, function* () {
160
+ var _a;
161
+ const items = fs.readdirSync((_a = params === null || params === void 0 ? void 0 : params[0]) !== null && _a !== void 0 ? _a : this.cwd); // 读取目录内容
162
+ const v = this.cols_handle(" " + items.join(" "));
163
+ this.send_and_enter(v);
164
+ }));
111
165
  }
112
166
  // cmd 命令 参数预测 只要是参数都可能是本目录下的文件名所以可以检测一下
113
167
  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); // 读取目录内容
168
+ const items = fs.readdirSync(this.cwd); // 读取目录内容
119
169
  if (!this.word_detection) {
120
170
  this.word_detection = new word_detection_js_1.word_detection_js();
121
171
  for (const item of items) {
@@ -130,6 +180,12 @@ class PtyShell {
130
180
  }
131
181
  return v;
132
182
  }
183
+ get not_write() {
184
+ return this._not_write;
185
+ }
186
+ set not_write(value) {
187
+ this._not_write = value;
188
+ }
133
189
  /**
134
190
  * public method
135
191
  */
@@ -143,7 +199,9 @@ class PtyShell {
143
199
  }
144
200
  add_cmd_handle(exe_cmd, handle) {
145
201
  this.cmd_exec_map.set(exe_cmd, handle);
146
- this.cmd_set.add(exe_cmd);
202
+ }
203
+ add_js_child(name, child) {
204
+ this.js_child_map.set(name, child);
147
205
  }
148
206
  close() {
149
207
  this.is_running = false;
@@ -162,7 +220,7 @@ class PtyShell {
162
220
  const max_index = str.length - 1;
163
221
  const list = [];
164
222
  let last_index = 0; // 上一次位置
165
- let index = PtyShell.readFullCharIndex(str, 0, this.cols);
223
+ let index = char_util_1.CharUtil.readFullCharIndex(str, 0, this.cols);
166
224
  let count = 0;
167
225
  while (index < max_index) {
168
226
  if (count > max_index)
@@ -174,21 +232,21 @@ class PtyShell {
174
232
  if (this.is_empty(str[f])) {
175
233
  list.push(str.substring(last_index, f + 1));
176
234
  last_index = f + 1;
177
- index = f + 1 + PtyShell.readFullCharIndex(str, f + 1, this.cols);
235
+ index = f + 1 + char_util_1.CharUtil.readFullCharIndex(str, f + 1, this.cols);
178
236
  continue;
179
237
  }
180
238
  if (f === last_index) {
181
239
  // 最后一位 直接把本行全部添加进去
182
240
  list.push(str.substring(last_index, index));
183
241
  last_index = index;
184
- index = index + PtyShell.readFullCharIndex(str, index, this.cols);
242
+ index = index + char_util_1.CharUtil.readFullCharIndex(str, index, this.cols);
185
243
  }
186
244
  }
187
245
  }
188
246
  else {
189
247
  list.push(str.substring(last_index, index));
190
248
  last_index = index;
191
- index = index + PtyShell.readFullCharIndex(str, index + 1, this.cols);
249
+ index = index + char_util_1.CharUtil.readFullCharIndex(str, index + 1, this.cols);
192
250
  }
193
251
  }
194
252
  if (index >= max_index) {
@@ -202,8 +260,10 @@ class PtyShell {
202
260
  */
203
261
  write(data) {
204
262
  return __awaiter(this, void 0, void 0, function* () {
205
- if (this.child && this.is_pty) {
206
- // 终端shell 完全 托管给 别的程序
263
+ if (this._not_write)
264
+ return;
265
+ if (this.node_pty_child != null) {
266
+ // 终端shell 完全 托管给 别的程序 只有 pty 的子程序可以 其他 需要pty-shell充当编辑器
207
267
  this.spawn_write(data);
208
268
  return;
209
269
  }
@@ -252,52 +312,6 @@ class PtyShell {
252
312
  }
253
313
  });
254
314
  }
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
315
  /**
302
316
  * private method
303
317
  */
@@ -332,20 +346,33 @@ class PtyShell {
332
346
  }
333
347
  close_child(code) {
334
348
  this.child_now_line = '';
335
- if (this.child) {
349
+ let child = this.child;
350
+ if (this.node_pty_child) {
351
+ child = this.node_pty_child;
352
+ }
353
+ if (child) {
336
354
  // SystemUtil.killProcess(this.child.pid);
337
- const pid = this.child.pid;
355
+ const pid = child.pid;
338
356
  if (this.on_child_kill) {
339
357
  this.exec_end_call(code, pid);
340
358
  }
341
359
  else {
342
- this.child.kill(); // 不同平台信号不同 win 默认 SIGHUP
360
+ child.kill(); // 不同平台信号不同 win 默认 SIGHUP
343
361
  }
344
- this.child = undefined;
345
362
  }
363
+ if (this.js_func_child) {
364
+ this.js_func_child.kill();
365
+ }
366
+ this.child = undefined;
367
+ this.node_pty_child = null;
368
+ this.js_func_child = null;
369
+ }
370
+ have_child() {
371
+ return this.child != null || this.node_pty_child != null || this.js_func_child != null;
346
372
  }
347
373
  send_and_enter(str, send_prompt = false) {
348
374
  try {
375
+ const have_child = this.have_child();
349
376
  if (typeof str == "string") {
350
377
  const list = [];
351
378
  let i = 0;
@@ -365,7 +392,7 @@ class PtyShell {
365
392
  }
366
393
  if (i === 0 || i !== last_i)
367
394
  list.push(str.substring(i));
368
- if (this.child) {
395
+ if (have_child) {
369
396
  // 添加子进程的提示换行
370
397
  this.child_now_line = list[list.length - 1];
371
398
  }
@@ -380,7 +407,7 @@ class PtyShell {
380
407
  }
381
408
  this.next_not_enter = str.endsWith('\n\r') || str.endsWith('\r\n'); // 下一次不用换行了
382
409
  }
383
- if (!this.child || send_prompt) {
410
+ if (!have_child || send_prompt) {
384
411
  this.on_call(`${this.enter_prompt}`);
385
412
  }
386
413
  this.clear_line();
@@ -392,8 +419,9 @@ class PtyShell {
392
419
  // 重新更新显示本行 也许可以更节省的更新 文本 powershell 这样的每次都是全部更新 暂时和他一样
393
420
  update_line(param) {
394
421
  var _a, _b;
395
- 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; // 字符串前面的字符数量
422
+ const have_child = this.have_child();
423
+ const prompt = !have_child ? this.raw_prompt : this.child_now_line;
424
+ let len = (!have_child ? this.prompt_call_len : char_util_1.CharUtil.get_full_char_num(prompt)) + this.line_char_index; // 字符串前面的字符数量
397
425
  if (param && param.line_add_num) {
398
426
  len += param.line_add_num;
399
427
  }
@@ -421,7 +449,7 @@ class PtyShell {
421
449
  get line_char_index() {
422
450
  if (this.line_index === -1)
423
451
  return 0;
424
- return PtyShell.get_full_char_num(this.line.substring(0, this.line_index + 1));
452
+ return char_util_1.CharUtil.get_full_char_num(this.line.substring(0, this.line_index + 1));
425
453
  }
426
454
  ctrl_exec(str) {
427
455
  let cancel_selected = true; // 取消选中
@@ -483,7 +511,7 @@ class PtyShell {
483
511
  break;
484
512
  }
485
513
  this.line_index++;
486
- const len = PtyShell.get_full_char_num(this.line[this.line_index]);
514
+ const len = char_util_1.CharUtil.get_full_char_num(this.line[this.line_index]);
487
515
  if (this.select_line) {
488
516
  this.update_line({ line_add_num: 1 });
489
517
  break;
@@ -497,7 +525,7 @@ class PtyShell {
497
525
  if (this.line_index === -1) {
498
526
  break;
499
527
  }
500
- const len = PtyShell.get_full_char_num(this.line[this.line_index]);
528
+ const len = char_util_1.CharUtil.get_full_char_num(this.line[this.line_index]);
501
529
  this.line_index--;
502
530
  if (this.select_line) {
503
531
  this.update_line({ line_add_num: 1 });
@@ -550,7 +578,7 @@ class PtyShell {
550
578
  this.cancel_selected();
551
579
  this.update_line({ line_add_num: 1 });
552
580
  }
553
- else if (this.child) {
581
+ else if (this.have_child()) {
554
582
  this.close_child(0);
555
583
  return;
556
584
  }
@@ -725,20 +753,16 @@ class PtyShell {
725
753
  // 解析和执行命令 执行完会自动换行的
726
754
  parse_exec() {
727
755
  return __awaiter(this, void 0, void 0, function* () {
756
+ var _a;
728
757
  // const line = this.delete_all_enter(this.line);
729
- if (!this.line && !this.child) {
758
+ if (!this.line && !this.have_child()) {
730
759
  this.send_and_enter("");
731
760
  this.clear_line();
732
761
  return;
733
762
  }
734
763
  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
- // 把数据给正在运行的别的程序
764
+ if (this.have_child()) {
765
+ // 把数据给正在运行的别的程序 但是肯定不是 pty 的pty 不需要pty-shell 做命令编辑器
742
766
  this.spawn_write(`${this.line}\n`);
743
767
  this.clear_line();
744
768
  return;
@@ -772,7 +796,7 @@ class PtyShell {
772
796
  exe = r.exe_cmd;
773
797
  params = r.params;
774
798
  }
775
- if (this.cmd_set.has(exe)) {
799
+ if (this.cmd_exec_map.has(exe)) {
776
800
  // 检测某个已经有预处理的命令 包括用户自定义的
777
801
  yield this.exec_cmd(exe, params);
778
802
  // 不用再继续了
@@ -780,12 +804,26 @@ class PtyShell {
780
804
  this.exec_end_call(0);
781
805
  return;
782
806
  }
783
- this.spawn(exe, params, use_noe_pty);
807
+ if (this.js_child_map.has(exe)) {
808
+ const c_ = this.js_child_map.get(exe);
809
+ this.js_func_child = new c_(this, () => {
810
+ this.send_and_enter("", true);
811
+ this.next_not_enter = false; // 下一次的换行输出 上一次没有换行
812
+ this.close_child();
813
+ }, (str) => {
814
+ this.send_and_enter(str);
815
+ }, params);
816
+ this.js_func_child.init();
817
+ return;
818
+ }
819
+ else {
820
+ this.spawn(exe, params, use_noe_pty);
821
+ }
784
822
  this.clear_line();
785
823
  }
786
824
  catch (e) {
787
825
  // console.log("子线程执行异常", e);
788
- this.send_and_enter(e.message);
826
+ this.send_and_enter((_a = e.message) !== null && _a !== void 0 ? _a : e);
789
827
  this.exec_end_call(-1);
790
828
  }
791
829
  });
@@ -813,18 +851,22 @@ class PtyShell {
813
851
  });
814
852
  }
815
853
  spawn_write(str) {
816
- if (this.is_pty) {
817
- this.child.write(str);
854
+ if (this.node_pty_child) {
855
+ this.node_pty_child.write(str);
856
+ // this.child.write(str);
818
857
  }
819
- else {
858
+ else if (this.child) {
820
859
  this.child.stdin.write(str);
821
860
  }
822
- }
823
- spawn(exe, params, use_noe_pty = true, spawn_option) {
824
- if (this.not_use_node_pre_cmd_exec) {
825
- this.send_and_enter(`not_use_node_pre_cmd_exec is true`);
826
- return;
861
+ else if (this.js_func_child) {
862
+ this.js_func_child.write(str);
827
863
  }
864
+ }
865
+ spawn(exe, params, use_noe_pty = true) {
866
+ // if (this.not_use_node_pre_cmd_exec) {
867
+ // this.send_and_enter(`not_use_node_pre_cmd_exec is true`);
868
+ // return;
869
+ // }
828
870
  // this.send_and_enter(""); //
829
871
  // if (!this.child) {
830
872
  // this.on_call(`\n\r`); // 先换个行
@@ -834,30 +876,40 @@ class PtyShell {
834
876
  // exe += '.exe';
835
877
  // }
836
878
  this.on_call(`\n\r`); // 先换个行
837
- 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));
838
- this.child.onData((data) => {
879
+ this.node_pty_child = this.node_pty.spawn(exe, params, {
880
+ name: 'xterm-color',
881
+ cols: this.cols,
882
+ rows: this.rows,
883
+ cwd: this.cwd, // 设置子进程的工作目录
884
+ useConptyDll: false,
885
+ useConpty: process.env.NODE_ENV !== "production" ? false : undefined, // conpty 可以支持 bash 等命令 从 Windows 10 版本 1809 开始提供 , 但是如果使用了 powershell 这个也就没有必要了,而且设置为false才能使用debug模式运行
886
+ env: Object.assign(Object.assign({}, process.env), this.env), // 传递环境变量
887
+ });
888
+ this.node_pty_child.onData((data) => {
839
889
  this.on_call(data.toString());
840
890
  if (this.on_call_child_raw) {
841
891
  this.on_call_child_raw(data);
842
892
  }
843
893
  });
844
- this.child.onExit(({ exitCode, signal }) => {
894
+ this.node_pty_child.onExit(({ exitCode, signal }) => {
845
895
  this.close_child(exitCode);
846
896
  this.send_and_enter("");
847
897
  // this.send_and_enter(`pty with ${exitCode}`);
848
898
  this.next_not_enter = false; // 下一次的换行输出 上一次没有换行
849
899
  });
850
- this.is_pty = true;
900
+ // this.is_pty = true;
851
901
  }
852
902
  else {
853
- this.is_pty = false;
903
+ // this.is_pty = false;
854
904
  // 其他的没有必要再创建一个 tty 都是资源消耗
855
- this.child = this.node_require.child_process.spawn(exe, params, Object.assign({
905
+ this.child = child_process.spawn(exe, params, {
856
906
  // shell:getShell(),
857
- cwd: this.cwd, env: Object.assign(Object.assign(Object.assign({}, process.env), this.env), { LANG: 'en_US.UTF-8' }),
907
+ cwd: this.cwd, // 设置子进程的工作目录
908
+ env: Object.assign(Object.assign(Object.assign({}, process.env), this.env), { LANG: 'en_US.UTF-8' }), // 传递环境变量
858
909
  // stdio: 'inherit' // 让子进程的输入输出与父进程共享 pipe ignore inherit
859
910
  // timeout: 5000, // 设置超时为 5 秒
860
- maxBuffer: 1024 * 1024 * 10 }, spawn_option));
911
+ // maxBuffer: 1024 * 1024 * 10// 设置缓冲区为 10 MB
912
+ });
861
913
  // 设置编码为 'utf8',确保输出按 UTF-8 编码解析
862
914
  this.child.stdout.setEncoding('utf8');
863
915
  this.child.stdout.on('data', (data) => {
@@ -893,58 +945,20 @@ class PtyShell {
893
945
  }
894
946
  exec_cmd(exe, params) {
895
947
  return __awaiter(this, void 0, void 0, function* () {
948
+ var _a;
896
949
  try {
897
950
  const handle = this.cmd_exec_map.get(exe);
898
- if (exe !== 'cd' && handle) {
899
- // 如果用户有了就用用户的 不用系统自己的 但是 cd 命令排除在外
900
- yield handle(params, (data) => {
901
- this.send_and_enter(data, true);
951
+ if (handle) {
952
+ // 如果用户有了就用用户的 不用系统自己的
953
+ yield handle(params, (data, enter) => {
954
+ this.send_and_enter(data, enter);
902
955
  });
903
956
  return true;
904
957
  }
905
- switch (exe) {
906
- case 'pwd':
907
- {
908
- this.send_and_enter(`${this.cwd}`);
909
- }
910
- return true;
911
- case 'cd':
912
- {
913
- let p;
914
- if (!this.not_use_node_pre_cmd_exec) {
915
- // 有node环境可以检测一下
916
- p = this.node_require.path.isAbsolute(params[0]) ? params[0] : this.node_require.path.join(this.cwd, params[0]);
917
- if (!this.node_require.fs.existsSync(p)) {
918
- this.send_and_enter(`not directory ${p}`);
919
- }
920
- }
921
- else {
922
- // 没有node环境只能这样了 todo 对于 .. 路径有问题
923
- p = (0, path_util_1.path_join)(this.cwd, params[0]);
924
- }
925
- this.cwd = p;
926
- this.send_and_enter(``);
927
- this.word_detection = undefined; // 清空检测器
928
- }
929
- return true;
930
- case 'ls':
931
- {
932
- if (this.not_use_node_pre_cmd_exec) {
933
- return false; // 让其它方式处理
934
- }
935
- const items = this.node_require.fs.readdirSync(this.cwd); // 读取目录内容
936
- const v = this.cols_handle(" " + items.join(" "));
937
- this.send_and_enter(v);
938
- }
939
- return true;
940
- default:
941
- return false; // 让其它方式处理
942
- }
943
958
  }
944
959
  catch (e) {
945
- this.send_and_enter(JSON.stringify(e));
960
+ this.send_and_enter((_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : e);
946
961
  }
947
- return false; // 让其它方式处理
948
962
  });
949
963
  }
950
964
  // 解析命令与参数
@@ -1062,3 +1076,7 @@ class PtyShell {
1062
1076
  }
1063
1077
  }
1064
1078
  exports.PtyShell = PtyShell;
1079
+ __exportStar(require("./type"), exports);
1080
+ __exportStar(require("./char.util"), exports);
1081
+ __exportStar(require("./path_util"), exports);
1082
+ __exportStar(require("./word_detection_js"), exports);
package/dist/type.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { PtyShell } from "./index";
2
+ export interface child_func_type {
3
+ write(str: string): void;
4
+ kill(): void;
5
+ init(): void;
6
+ }
7
+ export type child_func_constructor = new (pty_shell: PtyShell, 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.2",
3
+ "version": "1.4.0",
4
4
  "description": "a virtual PTY shell for javaScript",
5
5
  "author": "xiaobaidadada",
6
6
  "main": "dist/index.js",