index.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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;