1 | "use strict";
|
---|
2 | /***
|
---|
3 | * Node External Editor
|
---|
4 | *
|
---|
5 | * Kevin Gravier <kevin@mrkmg.com>
|
---|
6 | * MIT 2019
|
---|
7 | */
|
---|
8 | Object.defineProperty(exports, "__esModule", { value: true });
|
---|
9 | var chardet_1 = require("chardet");
|
---|
10 | var child_process_1 = require("child_process");
|
---|
11 | var fs_1 = require("fs");
|
---|
12 | var iconv_lite_1 = require("iconv-lite");
|
---|
13 | var tmp_1 = require("tmp");
|
---|
14 | var CreateFileError_1 = require("./errors/CreateFileError");
|
---|
15 | exports.CreateFileError = CreateFileError_1.CreateFileError;
|
---|
16 | var LaunchEditorError_1 = require("./errors/LaunchEditorError");
|
---|
17 | exports.LaunchEditorError = LaunchEditorError_1.LaunchEditorError;
|
---|
18 | var ReadFileError_1 = require("./errors/ReadFileError");
|
---|
19 | exports.ReadFileError = ReadFileError_1.ReadFileError;
|
---|
20 | var RemoveFileError_1 = require("./errors/RemoveFileError");
|
---|
21 | exports.RemoveFileError = RemoveFileError_1.RemoveFileError;
|
---|
22 | function edit(text, fileOptions) {
|
---|
23 | if (text === void 0) { text = ""; }
|
---|
24 | var editor = new ExternalEditor(text, fileOptions);
|
---|
25 | editor.run();
|
---|
26 | editor.cleanup();
|
---|
27 | return editor.text;
|
---|
28 | }
|
---|
29 | exports.edit = edit;
|
---|
30 | function editAsync(text, callback, fileOptions) {
|
---|
31 | if (text === void 0) { text = ""; }
|
---|
32 | var editor = new ExternalEditor(text, fileOptions);
|
---|
33 | editor.runAsync(function (err, result) {
|
---|
34 | if (err) {
|
---|
35 | setImmediate(callback, err, null);
|
---|
36 | }
|
---|
37 | else {
|
---|
38 | try {
|
---|
39 | editor.cleanup();
|
---|
40 | setImmediate(callback, null, result);
|
---|
41 | }
|
---|
42 | catch (cleanupError) {
|
---|
43 | setImmediate(callback, cleanupError, null);
|
---|
44 | }
|
---|
45 | }
|
---|
46 | });
|
---|
47 | }
|
---|
48 | exports.editAsync = editAsync;
|
---|
49 | var ExternalEditor = /** @class */ (function () {
|
---|
50 | function ExternalEditor(text, fileOptions) {
|
---|
51 | if (text === void 0) { text = ""; }
|
---|
52 | this.text = "";
|
---|
53 | this.fileOptions = {};
|
---|
54 | this.text = text;
|
---|
55 | if (fileOptions) {
|
---|
56 | this.fileOptions = fileOptions;
|
---|
57 | }
|
---|
58 | this.determineEditor();
|
---|
59 | this.createTemporaryFile();
|
---|
60 | }
|
---|
61 | ExternalEditor.splitStringBySpace = function (str) {
|
---|
62 | var pieces = [];
|
---|
63 | var currentString = "";
|
---|
64 | for (var strIndex = 0; strIndex < str.length; strIndex++) {
|
---|
65 | var currentLetter = str[strIndex];
|
---|
66 | if (strIndex > 0 && currentLetter === " " && str[strIndex - 1] !== "\\" && currentString.length > 0) {
|
---|
67 | pieces.push(currentString);
|
---|
68 | currentString = "";
|
---|
69 | }
|
---|
70 | else {
|
---|
71 | currentString += currentLetter;
|
---|
72 | }
|
---|
73 | }
|
---|
74 | if (currentString.length > 0) {
|
---|
75 | pieces.push(currentString);
|
---|
76 | }
|
---|
77 | return pieces;
|
---|
78 | };
|
---|
79 | Object.defineProperty(ExternalEditor.prototype, "temp_file", {
|
---|
80 | get: function () {
|
---|
81 | console.log("DEPRECATED: temp_file. Use tempFile moving forward.");
|
---|
82 | return this.tempFile;
|
---|
83 | },
|
---|
84 | enumerable: true,
|
---|
85 | configurable: true
|
---|
86 | });
|
---|
87 | Object.defineProperty(ExternalEditor.prototype, "last_exit_status", {
|
---|
88 | get: function () {
|
---|
89 | console.log("DEPRECATED: last_exit_status. Use lastExitStatus moving forward.");
|
---|
90 | return this.lastExitStatus;
|
---|
91 | },
|
---|
92 | enumerable: true,
|
---|
93 | configurable: true
|
---|
94 | });
|
---|
95 | ExternalEditor.prototype.run = function () {
|
---|
96 | this.launchEditor();
|
---|
97 | this.readTemporaryFile();
|
---|
98 | return this.text;
|
---|
99 | };
|
---|
100 | ExternalEditor.prototype.runAsync = function (callback) {
|
---|
101 | var _this = this;
|
---|
102 | try {
|
---|
103 | this.launchEditorAsync(function () {
|
---|
104 | try {
|
---|
105 | _this.readTemporaryFile();
|
---|
106 | setImmediate(callback, null, _this.text);
|
---|
107 | }
|
---|
108 | catch (readError) {
|
---|
109 | setImmediate(callback, readError, null);
|
---|
110 | }
|
---|
111 | });
|
---|
112 | }
|
---|
113 | catch (launchError) {
|
---|
114 | setImmediate(callback, launchError, null);
|
---|
115 | }
|
---|
116 | };
|
---|
117 | ExternalEditor.prototype.cleanup = function () {
|
---|
118 | this.removeTemporaryFile();
|
---|
119 | };
|
---|
120 | ExternalEditor.prototype.determineEditor = function () {
|
---|
121 | var editor = process.env.VISUAL ? process.env.VISUAL :
|
---|
122 | process.env.EDITOR ? process.env.EDITOR :
|
---|
123 | /^win/.test(process.platform) ? "notepad" :
|
---|
124 | "vim";
|
---|
125 | var editorOpts = ExternalEditor.splitStringBySpace(editor).map(function (piece) { return piece.replace("\\ ", " "); });
|
---|
126 | var bin = editorOpts.shift();
|
---|
127 | this.editor = { args: editorOpts, bin: bin };
|
---|
128 | };
|
---|
129 | ExternalEditor.prototype.createTemporaryFile = function () {
|
---|
130 | try {
|
---|
131 | this.tempFile = tmp_1.tmpNameSync(this.fileOptions);
|
---|
132 | var opt = { encoding: "utf8" };
|
---|
133 | if (this.fileOptions.hasOwnProperty("mode")) {
|
---|
134 | opt.mode = this.fileOptions.mode;
|
---|
135 | }
|
---|
136 | fs_1.writeFileSync(this.tempFile, this.text, opt);
|
---|
137 | }
|
---|
138 | catch (createFileError) {
|
---|
139 | throw new CreateFileError_1.CreateFileError(createFileError);
|
---|
140 | }
|
---|
141 | };
|
---|
142 | ExternalEditor.prototype.readTemporaryFile = function () {
|
---|
143 | try {
|
---|
144 | var tempFileBuffer = fs_1.readFileSync(this.tempFile);
|
---|
145 | if (tempFileBuffer.length === 0) {
|
---|
146 | this.text = "";
|
---|
147 | }
|
---|
148 | else {
|
---|
149 | var encoding = chardet_1.detect(tempFileBuffer).toString();
|
---|
150 | if (!iconv_lite_1.encodingExists(encoding)) {
|
---|
151 | // Probably a bad idea, but will at least prevent crashing
|
---|
152 | encoding = "utf8";
|
---|
153 | }
|
---|
154 | this.text = iconv_lite_1.decode(tempFileBuffer, encoding);
|
---|
155 | }
|
---|
156 | }
|
---|
157 | catch (readFileError) {
|
---|
158 | throw new ReadFileError_1.ReadFileError(readFileError);
|
---|
159 | }
|
---|
160 | };
|
---|
161 | ExternalEditor.prototype.removeTemporaryFile = function () {
|
---|
162 | try {
|
---|
163 | fs_1.unlinkSync(this.tempFile);
|
---|
164 | }
|
---|
165 | catch (removeFileError) {
|
---|
166 | throw new RemoveFileError_1.RemoveFileError(removeFileError);
|
---|
167 | }
|
---|
168 | };
|
---|
169 | ExternalEditor.prototype.launchEditor = function () {
|
---|
170 | try {
|
---|
171 | var editorProcess = child_process_1.spawnSync(this.editor.bin, this.editor.args.concat([this.tempFile]), { stdio: "inherit" });
|
---|
172 | this.lastExitStatus = editorProcess.status;
|
---|
173 | }
|
---|
174 | catch (launchError) {
|
---|
175 | throw new LaunchEditorError_1.LaunchEditorError(launchError);
|
---|
176 | }
|
---|
177 | };
|
---|
178 | ExternalEditor.prototype.launchEditorAsync = function (callback) {
|
---|
179 | var _this = this;
|
---|
180 | try {
|
---|
181 | var editorProcess = child_process_1.spawn(this.editor.bin, this.editor.args.concat([this.tempFile]), { stdio: "inherit" });
|
---|
182 | editorProcess.on("exit", function (code) {
|
---|
183 | _this.lastExitStatus = code;
|
---|
184 | setImmediate(callback);
|
---|
185 | });
|
---|
186 | }
|
---|
187 | catch (launchError) {
|
---|
188 | throw new LaunchEditorError_1.LaunchEditorError(launchError);
|
---|
189 | }
|
---|
190 | };
|
---|
191 | return ExternalEditor;
|
---|
192 | }());
|
---|
193 | exports.ExternalEditor = ExternalEditor;
|
---|