leetcode-cli
Version:
A cli tool to enjoy leetcode!
200 lines (181 loc) • 5.7 kB
JavaScript
'use strict';
var util = require('util');
var _ = require('underscore');
var childProcess = require('child_process');
var h = require('../helper');
var file = require('../file');
var chalk = require('../chalk');
var icon = require('../icon');
var log = require('../log');
var config = require('../config');
var core = require('../core');
var session = require('../session');
const cmd = {
command: 'show [keyword]',
aliases: ['view', 'pick'],
desc: 'Show question',
builder: function(yargs) {
return yargs
.option('c', {
alias: 'codeonly',
type: 'boolean',
default: false,
describe: 'Only show code template'
})
.option('e', {
alias: 'editor',
type: 'string',
describe: 'Open source code in editor'
})
.option('g', {
alias: 'gen',
type: 'boolean',
default: false,
describe: 'Generate source code'
})
.option('l', {
alias: 'lang',
type: 'string',
default: config.code.lang,
describe: 'Programming language of the source code',
choices: config.sys.langs
})
.option('o', {
alias: 'outdir',
type: 'string',
describe: 'Where to save source code',
default: '.'
})
.option('q', core.filters.query)
.option('t', core.filters.tag)
.option('x', {
alias: 'extra',
type: 'boolean',
default: false,
describe: 'Show extra question details in source code'
})
.positional('keyword', {
type: 'string',
default: '',
describe: 'Show question by name or id'
})
.example(chalk.yellow('leetcode show 1'), 'Show question 1')
.example(chalk.yellow('leetcode show 1 -gx -l java'), 'Show question 1 and generate Java code')
.example(chalk.yellow('leetcode show 1 -gxe'), 'Open generated code in editor')
.example('', '')
.example(chalk.yellow('leetcode show'), 'Show random question')
.example(chalk.yellow('leetcode show -q h'), 'Show random hard question')
.example(chalk.yellow('leetcode show -t google'), 'Show random question from Google (require plugin)');
}
};
function genFileName(problem, opts) {
const path = require('path');
const params = [
file.fmt(config.file.show, problem),
'',
h.langToExt(opts.lang)
];
// try new name to avoid overwrite by mistake
for (let i = 0; ; ++i) {
const name = path.join(opts.outdir, params.join('.').replace(/\.+/g, '.'));
if (!file.exist(name))
return name;
params[1] = i;
}
}
function showProblem(problem, argv) {
const taglist = [problem.category]
.concat(problem.companies || [])
.concat(problem.tags || [])
.map(x => h.badge(x, 'blue'))
.join(' ');
const langlist = problem.templates
.map(x => h.badge(x.value, 'yellow'))
.sort()
.join(' ');
let code;
const needcode = argv.gen || argv.codeonly;
if (needcode) {
const template = problem.templates.find(x => x.value === argv.lang);
if (!template) {
log.fail('Not supported language "' + argv.lang + '"');
log.warn('Supported languages: ' + langlist);
return;
}
const opts = {
lang: argv.lang,
code: template.defaultCode,
tpl: argv.extra ? 'detailed' : 'codeonly'
};
code = core.exportProblem(problem, opts);
}
let filename;
if (argv.gen) {
file.mkdir(argv.outdir);
filename = genFileName(problem, argv);
file.write(filename, code);
if (argv.editor !== undefined) {
childProcess.spawn(argv.editor || config.code.editor, [filename], {
// in case your editor of choice is vim or emacs
stdio: 'inherit'
});
}
} else {
if (argv.codeonly) {
log.info(chalk.yellow(code));
return;
}
}
log.printf('[%s] %s %s', problem.fid, problem.name,
(problem.starred ? chalk.yellow(icon.like) : icon.empty));
log.info();
log.info(chalk.underline(problem.link));
if (argv.extra) {
log.info();
log.info('Tags: ' + taglist);
log.info();
log.info('Langs: ' + langlist);
}
log.info();
log.printf('* %s', problem.category);
log.printf('* %s (%s%%)', h.prettyLevel(problem.level), problem.percent.toFixed(2));
if (filename)
log.printf('* Source Code: %s', chalk.yellow.underline(filename));
if (problem.totalAC)
log.printf('* Total Accepted: %s', problem.totalAC);
if (problem.totalSubmit)
log.printf('* Total Submissions: %s', problem.totalSubmit);
if (problem.testable && problem.testcase)
log.printf('* Testcase Example: %s', chalk.yellow(util.inspect(problem.testcase)));
log.info();
log.info(problem.desc);
}
cmd.handler = function(argv) {
session.argv = argv;
if (argv.keyword.length > 0) {
// show specific one
core.getProblem(argv.keyword, function(e, problem) {
if (e) return log.fail(e);
showProblem(problem, argv);
});
} else {
// show random one
core.filterProblems(argv, function(e, problems) {
if (e) return log.fail(e);
// random select one that not AC-ed yet
const user = session.getUser();
problems = problems.filter(function(x) {
if (x.state === 'ac') return false;
if (!user.paid && x.locked) return false;
return true;
});
if (problems.length === 0) return log.fail('Problem not found!');
const problem = _.sample(problems);
core.getProblem(problem, function(e, problem) {
if (e) return log.fail(e);
showProblem(problem, argv);
});
});
}
};
module.exports = cmd;