gogs-cli
Version:
Commandline interface for your Gogs needs
95 lines (83 loc) • 3.18 kB
JavaScript
;
const fs = require('fs');
const path = require('path');
const os = require('os');
const wrap = require('wrap-ansi');
const spawn = require('child_process').spawn;
const errors = require('./errors');
const DEFAULT_DELIMITER = '<!-- EVERYTHING BELOW THIS LINE IS CONSIDERED COMMENTS -->';
class EditorAborted extends errors.GogsCliError {
constructor(...args) {
super('Aborted due to empty message from editor', ...args);
}
}
class EditorNonZeroExitCode extends errors.GogsCliError {
constructor(exitCode, ...args) {
super('Aborted due to non-zero exit code from editor', ...args);
this.exitCode = exitCode;
}
}
/**
* Opens the editor of choice in the terminal to let the user insert
* text that is then returned in the given promise.
*
* If the user closes the editor without writing anything to the file,
* the operation is considered to be aborted and an instance of
* EditorAborted is thrown (through rejection).
*
* If the editor returns a non-zero code exit code,
* EditorNonZeroExitCode is thrown, where .exitcode is the exit code.
*
* **comment** is the comment to add to the editor. The first line of
* the editor is always empty to allow the user to immediately write
* text. All comments are placed under the first line. Each line of the
* comment should start with the **commentCharacter** variable so that
* they can be easily stripped from the rest of the content.
*
* The comment is hard wrapped to 80 characters automatically, with each
* wrapped line starting with the **commentCharacter**. Use a
* **commentCharacter** that is unusual to use in the given language.
*
* @param {String} filetype file extension, md, js, etc.
* @param {String} [comment=''] See section above.
* @param {String} [commentDelimiter='']
* @returns {Promise<String>}
*/
module.exports = function(filetype, comment = '', commentDelimiter = DEFAULT_DELIMITER) {
const editor = process.env.EDITOR || 'vi';
const extension = filetype.startsWith('.') ? filetype.slice(1) : filetype;
const tmpFilename = `${Date.now()}-gogs.cli-editor.${extension}`;
const tmpPath = path.join(os.tmpdir(), tmpFilename);
const formattedComment = comment === '' ?
'' :
'\n' + commentDelimiter + '\n' + wrap(comment, 80, {trim: false});
fs.writeFileSync(tmpPath, formattedComment);
const child = spawn(editor, [tmpPath], {
stdio: 'inherit'
});
return new Promise((resolve, reject) => {
child.on('exit', function(exitCode) {
if (exitCode !== 0)
return reject(new EditorNonZeroExitCode(exitCode));
let seenComment = false;
const content = fs
.readFileSync(tmpPath)
.toString()
.split('\n')
.filter(x => {
if (x === commentDelimiter)
seenComment = true;
return !seenComment;
})
.join('\n')
.trim();
if (content.length === 0)
return reject(new EditorAborted());
fs.unlinkSync(tmpPath);
resolve(content);
});
child.on('error', reject);
});
};
module.exports.EditorAborted = EditorAborted;
module.exports.EditorNonZeroExitCode = EditorNonZeroExitCode;