pty-shell 1.3.0 → 1.5.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/dist/index.d.ts +12 -0
- package/dist/index.js +230 -51
- package/dist/type.d.ts +3 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -82,6 +82,9 @@ export declare class PtyShell implements PtyShellUserMethod {
|
|
|
82
82
|
private history_line;
|
|
83
83
|
private history_line_index;
|
|
84
84
|
private history_line_max;
|
|
85
|
+
private _not_write;
|
|
86
|
+
get not_write(): boolean;
|
|
87
|
+
set not_write(value: boolean);
|
|
85
88
|
/**
|
|
86
89
|
* public method
|
|
87
90
|
*/
|
|
@@ -119,6 +122,15 @@ export declare class PtyShell implements PtyShellUserMethod {
|
|
|
119
122
|
private push_history_line;
|
|
120
123
|
private exec_end_call;
|
|
121
124
|
private parse_exec;
|
|
125
|
+
/**
|
|
126
|
+
* 解析组合命令,按 ; && || 分隔,返回命令列表
|
|
127
|
+
* 支持引号内的分隔符不被拆分
|
|
128
|
+
*/
|
|
129
|
+
private parse_combined_commands;
|
|
130
|
+
/**
|
|
131
|
+
* 同步方式执行子进程(用于组合命令),返回退出码
|
|
132
|
+
*/
|
|
133
|
+
private spawn_sync;
|
|
122
134
|
private multiple_line;
|
|
123
135
|
private spawn_write;
|
|
124
136
|
private spawn;
|
package/dist/index.js
CHANGED
|
@@ -138,6 +138,7 @@ class PtyShell {
|
|
|
138
138
|
this.history_line = [];
|
|
139
139
|
this.history_line_index = -1;
|
|
140
140
|
this.history_line_max = 20;
|
|
141
|
+
this._not_write = false;
|
|
141
142
|
this.next_not_enter = false;
|
|
142
143
|
this.reset_option(param);
|
|
143
144
|
this.on_call(this.raw_prompt);
|
|
@@ -149,6 +150,7 @@ class PtyShell {
|
|
|
149
150
|
const p = path.isAbsolute(params[0]) ? params[0] : path.join(this.cwd, params[0]);
|
|
150
151
|
if (!fs.existsSync(p)) {
|
|
151
152
|
this.send_and_enter(`not directory ${p}`);
|
|
153
|
+
return;
|
|
152
154
|
}
|
|
153
155
|
this.cwd = p;
|
|
154
156
|
this.send_and_enter(``);
|
|
@@ -178,6 +180,12 @@ class PtyShell {
|
|
|
178
180
|
}
|
|
179
181
|
return v;
|
|
180
182
|
}
|
|
183
|
+
get not_write() {
|
|
184
|
+
return this._not_write;
|
|
185
|
+
}
|
|
186
|
+
set not_write(value) {
|
|
187
|
+
this._not_write = value;
|
|
188
|
+
}
|
|
181
189
|
/**
|
|
182
190
|
* public method
|
|
183
191
|
*/
|
|
@@ -252,8 +260,10 @@ class PtyShell {
|
|
|
252
260
|
*/
|
|
253
261
|
write(data) {
|
|
254
262
|
return __awaiter(this, void 0, void 0, function* () {
|
|
255
|
-
if (this.
|
|
256
|
-
|
|
263
|
+
if (this._not_write)
|
|
264
|
+
return;
|
|
265
|
+
if (this.node_pty_child != null) {
|
|
266
|
+
// 终端shell 完全 托管给 别的程序 只有 pty 的子程序可以 其他 需要pty-shell充当编辑器
|
|
257
267
|
this.spawn_write(data);
|
|
258
268
|
return;
|
|
259
269
|
}
|
|
@@ -362,6 +372,7 @@ class PtyShell {
|
|
|
362
372
|
}
|
|
363
373
|
send_and_enter(str, send_prompt = false) {
|
|
364
374
|
try {
|
|
375
|
+
const have_child = this.have_child();
|
|
365
376
|
if (typeof str == "string") {
|
|
366
377
|
const list = [];
|
|
367
378
|
let i = 0;
|
|
@@ -381,7 +392,7 @@ class PtyShell {
|
|
|
381
392
|
}
|
|
382
393
|
if (i === 0 || i !== last_i)
|
|
383
394
|
list.push(str.substring(i));
|
|
384
|
-
if (
|
|
395
|
+
if (have_child) {
|
|
385
396
|
// 添加子进程的提示换行
|
|
386
397
|
this.child_now_line = list[list.length - 1];
|
|
387
398
|
}
|
|
@@ -396,7 +407,7 @@ class PtyShell {
|
|
|
396
407
|
}
|
|
397
408
|
this.next_not_enter = str.endsWith('\n\r') || str.endsWith('\r\n'); // 下一次不用换行了
|
|
398
409
|
}
|
|
399
|
-
if (!
|
|
410
|
+
if (!have_child || send_prompt) {
|
|
400
411
|
this.on_call(`${this.enter_prompt}`);
|
|
401
412
|
}
|
|
402
413
|
this.clear_line();
|
|
@@ -408,8 +419,9 @@ class PtyShell {
|
|
|
408
419
|
// 重新更新显示本行 也许可以更节省的更新 文本 powershell 这样的每次都是全部更新 暂时和他一样
|
|
409
420
|
update_line(param) {
|
|
410
421
|
var _a, _b;
|
|
411
|
-
const
|
|
412
|
-
|
|
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; // 字符串前面的字符数量
|
|
413
425
|
if (param && param.line_add_num) {
|
|
414
426
|
len += param.line_add_num;
|
|
415
427
|
}
|
|
@@ -566,7 +578,7 @@ class PtyShell {
|
|
|
566
578
|
this.cancel_selected();
|
|
567
579
|
this.update_line({ line_add_num: 1 });
|
|
568
580
|
}
|
|
569
|
-
else if (this.
|
|
581
|
+
else if (this.have_child()) {
|
|
570
582
|
this.close_child(0);
|
|
571
583
|
return;
|
|
572
584
|
}
|
|
@@ -741,6 +753,7 @@ class PtyShell {
|
|
|
741
753
|
// 解析和执行命令 执行完会自动换行的
|
|
742
754
|
parse_exec() {
|
|
743
755
|
return __awaiter(this, void 0, void 0, function* () {
|
|
756
|
+
var _a;
|
|
744
757
|
// const line = this.delete_all_enter(this.line);
|
|
745
758
|
if (!this.line && !this.have_child()) {
|
|
746
759
|
this.send_and_enter("");
|
|
@@ -748,61 +761,227 @@ class PtyShell {
|
|
|
748
761
|
return;
|
|
749
762
|
}
|
|
750
763
|
this.push_history_line(this.line);
|
|
751
|
-
|
|
764
|
+
if (this.have_child()) {
|
|
765
|
+
// 把数据给正在运行的别的程序 但是肯定不是 pty 的pty 不需要pty-shell 做命令编辑器
|
|
766
|
+
this.spawn_write(`${this.line}\n`);
|
|
767
|
+
this.clear_line();
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
752
770
|
this.history_line_index = -1;
|
|
753
|
-
|
|
771
|
+
// 解析组合命令(支持 ; && ||),解析出的 exe_cmd/params 来自 get_exec
|
|
772
|
+
const commands = this.parse_combined_commands(this.line);
|
|
773
|
+
if (commands.length === 0) {
|
|
774
|
+
this.send_and_enter("");
|
|
775
|
+
this.clear_line();
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
const resolved_list = [];
|
|
779
|
+
for (const cmd of commands) {
|
|
780
|
+
let { exe_cmd, params } = cmd;
|
|
754
781
|
let use_noe_pty = false;
|
|
782
|
+
// 1. check_exe_cmd(只调一次)
|
|
755
783
|
if (this.check_exe_cmd) {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
break;
|
|
766
|
-
case exec_type.not_pty:
|
|
767
|
-
use_noe_pty = true;
|
|
768
|
-
break;
|
|
769
|
-
default:
|
|
770
|
-
// 未知的不报错也不执行
|
|
771
|
-
this.exec_end_call(0);
|
|
772
|
-
return;
|
|
784
|
+
const v = yield this.check_exe_cmd(exe_cmd, params);
|
|
785
|
+
if (v === exec_type.not) {
|
|
786
|
+
this.send_and_enter(`not have permission to execute ${exe_cmd}`);
|
|
787
|
+
this.clear_line();
|
|
788
|
+
this.exec_end_call(-1);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
if (v === exec_type.not_pty) {
|
|
792
|
+
use_noe_pty = true;
|
|
773
793
|
}
|
|
774
794
|
}
|
|
795
|
+
// 2. cmd_replace(只调一次)
|
|
775
796
|
if (this.cmd_replace) {
|
|
776
|
-
const r = yield this.cmd_replace(
|
|
777
|
-
|
|
797
|
+
const r = yield this.cmd_replace(exe_cmd, params);
|
|
798
|
+
exe_cmd = r.exe_cmd;
|
|
778
799
|
params = r.params;
|
|
779
800
|
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
801
|
+
resolved_list.push({
|
|
802
|
+
exe_cmd,
|
|
803
|
+
params,
|
|
804
|
+
separator: cmd.separator,
|
|
805
|
+
use_noe_pty,
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
// 全部校验通过,按分隔符语义串行执行
|
|
809
|
+
let lastExitCode = 0;
|
|
810
|
+
for (let i = 0; i < resolved_list.length; i++) {
|
|
811
|
+
const cmd = resolved_list[i];
|
|
812
|
+
// 根据前一个命令的退出码和分隔符决定是否跳过当前命令
|
|
813
|
+
if (i > 0) {
|
|
814
|
+
const prevSep = resolved_list[i - 1].separator;
|
|
815
|
+
if (prevSep === '&&' && lastExitCode !== 0)
|
|
816
|
+
continue; // 前面失败,跳过
|
|
817
|
+
if (prevSep === '||' && lastExitCode === 0)
|
|
818
|
+
continue; // 前面成功,跳过
|
|
819
|
+
}
|
|
820
|
+
try {
|
|
821
|
+
if (this.cmd_exec_map.has(cmd.exe_cmd)) {
|
|
822
|
+
yield this.exec_cmd(cmd.exe_cmd, cmd.params);
|
|
823
|
+
lastExitCode = 0;
|
|
824
|
+
}
|
|
825
|
+
else if (this.js_child_map.has(cmd.exe_cmd)) {
|
|
826
|
+
// js_child 异步模式,不支持在组合命令中等待
|
|
827
|
+
if (resolved_list.length > 1) {
|
|
828
|
+
this.send_and_enter(`\x1b[31mjs_child not supported in combined commands: ${cmd.exe_cmd}\x1b[0m`);
|
|
829
|
+
lastExitCode = -1;
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
const c_ = this.js_child_map.get(cmd.exe_cmd);
|
|
833
|
+
this.js_func_child = new c_(this, () => {
|
|
834
|
+
this.send_and_enter("", true);
|
|
835
|
+
this.next_not_enter = false;
|
|
836
|
+
this.close_child();
|
|
837
|
+
}, (str) => {
|
|
838
|
+
this.send_and_enter(str);
|
|
839
|
+
}, cmd.params);
|
|
840
|
+
this.js_func_child.init();
|
|
841
|
+
this.clear_line();
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
// 子进程:组合命令需要同步等待,单命令走原有异步
|
|
846
|
+
if (resolved_list.length > 1) {
|
|
847
|
+
lastExitCode = yield this.spawn_sync(cmd.exe_cmd, cmd.params, cmd.use_noe_pty);
|
|
848
|
+
}
|
|
849
|
+
else {
|
|
850
|
+
this.spawn(cmd.exe_cmd, cmd.params, cmd.use_noe_pty);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
catch (e) {
|
|
855
|
+
this.send_and_enter((_a = e.message) !== null && _a !== void 0 ? _a : e);
|
|
856
|
+
lastExitCode = -1;
|
|
787
857
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
858
|
+
}
|
|
859
|
+
this.clear_line();
|
|
860
|
+
if (commands.length === 1) {
|
|
861
|
+
this.exec_end_call(lastExitCode === 0 ? 0 : -1);
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* 解析组合命令,按 ; && || 分隔,返回命令列表
|
|
867
|
+
* 支持引号内的分隔符不被拆分
|
|
868
|
+
*/
|
|
869
|
+
parse_combined_commands(line) {
|
|
870
|
+
const result = [];
|
|
871
|
+
let current = '';
|
|
872
|
+
let quote = null;
|
|
873
|
+
let i = 0;
|
|
874
|
+
while (i < line.length) {
|
|
875
|
+
const ch = line[i];
|
|
876
|
+
if (ch === '"' || ch === "'") {
|
|
877
|
+
if (quote === null) {
|
|
878
|
+
quote = ch;
|
|
798
879
|
}
|
|
799
|
-
|
|
800
|
-
|
|
880
|
+
else if (quote === ch) {
|
|
881
|
+
quote = null;
|
|
882
|
+
}
|
|
883
|
+
current += ch;
|
|
884
|
+
i++;
|
|
885
|
+
continue;
|
|
801
886
|
}
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
887
|
+
if (quote !== null) {
|
|
888
|
+
current += ch;
|
|
889
|
+
i++;
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
// &&
|
|
893
|
+
if (ch === '&' && i + 1 < line.length && line[i + 1] === '&') {
|
|
894
|
+
if (current.trim()) {
|
|
895
|
+
const r = this.get_exec(current.trim());
|
|
896
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: '&&' });
|
|
897
|
+
current = '';
|
|
898
|
+
}
|
|
899
|
+
i += 2;
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
// ||
|
|
903
|
+
if (ch === '|' && i + 1 < line.length && line[i + 1] === '|') {
|
|
904
|
+
if (current.trim()) {
|
|
905
|
+
const r = this.get_exec(current.trim());
|
|
906
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: '||' });
|
|
907
|
+
current = '';
|
|
908
|
+
}
|
|
909
|
+
i += 2;
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
// ;
|
|
913
|
+
if (ch === ';') {
|
|
914
|
+
if (current.trim()) {
|
|
915
|
+
const r = this.get_exec(current.trim());
|
|
916
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: ';' });
|
|
917
|
+
current = '';
|
|
918
|
+
}
|
|
919
|
+
i++;
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
current += ch;
|
|
923
|
+
i++;
|
|
924
|
+
}
|
|
925
|
+
if (current.trim()) {
|
|
926
|
+
const r = this.get_exec(current.trim());
|
|
927
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: '' });
|
|
928
|
+
}
|
|
929
|
+
return result;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* 同步方式执行子进程(用于组合命令),返回退出码
|
|
933
|
+
*/
|
|
934
|
+
spawn_sync(exe, params, use_noe_pty = false) {
|
|
935
|
+
return new Promise((resolve) => {
|
|
936
|
+
var _a, _b;
|
|
937
|
+
if ((use_noe_pty || ((_a = this.shell_set) === null || _a === void 0 ? void 0 : _a.has("*")) || ((_b = this.shell_set) === null || _b === void 0 ? void 0 : _b.has(exe))) && this.node_pty) {
|
|
938
|
+
this.on_call(`\n\r`);
|
|
939
|
+
this.node_pty_child = this.node_pty.spawn(exe, params, {
|
|
940
|
+
name: 'xterm-color',
|
|
941
|
+
cols: this.cols,
|
|
942
|
+
rows: this.rows,
|
|
943
|
+
cwd: this.cwd,
|
|
944
|
+
useConptyDll: false,
|
|
945
|
+
useConpty: process.env.NODE_ENV !== "production" ? false : undefined,
|
|
946
|
+
env: Object.assign(Object.assign({}, process.env), this.env),
|
|
947
|
+
});
|
|
948
|
+
this.node_pty_child.onData((data) => {
|
|
949
|
+
this.on_call(data.toString());
|
|
950
|
+
if (this.on_call_child_raw) {
|
|
951
|
+
this.on_call_child_raw(data);
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
this.node_pty_child.onExit(({ exitCode, signal }) => {
|
|
955
|
+
this.node_pty_child = null;
|
|
956
|
+
resolve(exitCode !== null && exitCode !== void 0 ? exitCode : -1);
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
else {
|
|
960
|
+
const child = child_process.spawn(exe, params, {
|
|
961
|
+
cwd: this.cwd,
|
|
962
|
+
env: Object.assign(Object.assign({}, process.env), this.env),
|
|
963
|
+
});
|
|
964
|
+
child.stdout.setEncoding('utf8');
|
|
965
|
+
child.stdout.on('data', (data) => {
|
|
966
|
+
this.send_and_enter(data.toString());
|
|
967
|
+
if (this.on_call_child_raw) {
|
|
968
|
+
this.on_call_child_raw(data);
|
|
969
|
+
}
|
|
970
|
+
});
|
|
971
|
+
child.stderr.on('data', (data) => {
|
|
972
|
+
this.send_and_enter(data.toString());
|
|
973
|
+
this.next_not_enter = false;
|
|
974
|
+
if (this.on_call_child_raw) {
|
|
975
|
+
this.on_call_child_raw(data);
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
child.on('exit', (code) => {
|
|
979
|
+
resolve(code !== null && code !== void 0 ? code : -1);
|
|
980
|
+
});
|
|
981
|
+
child.on('error', (error) => {
|
|
982
|
+
this.send_and_enter(error.message);
|
|
983
|
+
resolve(-1);
|
|
984
|
+
});
|
|
806
985
|
}
|
|
807
986
|
});
|
|
808
987
|
}
|
package/dist/type.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { PtyShell } from "./index";
|
|
1
2
|
export interface child_func_type {
|
|
2
3
|
write(str: string): void;
|
|
3
4
|
kill(): void;
|
|
5
|
+
init(): void;
|
|
4
6
|
}
|
|
5
|
-
export type child_func_constructor = new (exit_on: () => void, send: (str: string) => void, params: string[]) => child_func_type;
|
|
7
|
+
export type child_func_constructor = new (pty_shell: PtyShell, exit_on: () => void, send: (str: string) => void, params: string[]) => child_func_type;
|