1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-09 08:45:55 +02:00
joplin/CliClient/app/autocompletion.js
Laurent Cozic 71efff6827
Linter update (#1777)
* Update eslint config

* Applied linter to lib

* Applied eslint config to CliClient/app

* Removed prettier due to https://github.com/prettier/prettier/pull/4765

* First pass on test units

* Applied linter config to test units

* Applied eslint config to clipper

* Applied to plugin dir

* Applied to root of ElectronClient

* Applied on RN root

* Applied on CLI root

* Applied on Clipper root

* Applied config to tools

* test hook

* test hook

* test hook

* Added pre-commit hook

* Applied rule no-trailing-spaces

* Make sure root packages are installed when installing sub-dir

* Added doc
2019-07-30 09:35:42 +02:00

199 lines
5.6 KiB
JavaScript

var { app } = require('./app.js');
var Note = require('lib/models/Note.js');
var Folder = require('lib/models/Folder.js');
var Tag = require('lib/models/Tag.js');
var { cliUtils } = require('./cli-utils.js');
var yargParser = require('yargs-parser');
var fs = require('fs-extra');
async function handleAutocompletionPromise(line) {
// Auto-complete the command name
const names = await app().commandNames();
let words = getArguments(line);
//If there is only one word and it is not already a command name then you
//should look for commmands it could be
if (words.length == 1) {
if (names.indexOf(words[0]) === -1) {
let x = names.filter(n => n.indexOf(words[0]) === 0);
if (x.length === 1) {
return x[0] + ' ';
}
return x.length > 0 ? x.map(a => a + ' ') : line;
} else {
return line;
}
}
//There is more than one word and it is a command
const metadata = (await app().commandMetadata())[words[0]];
//If for some reason this command does not have any associated metadata
//just don't autocomplete. However, this should not happen.
if (metadata === undefined) {
return line;
}
//complete an option
let next = words.length > 1 ? words[words.length - 1] : '';
let l = [];
if (next[0] === '-') {
for (let i = 0; i < metadata.options.length; i++) {
const options = metadata.options[i][0].split(' ');
//if there are multiple options then they will be separated by comma and
//space. The comma should be removed
if (options[0][options[0].length - 1] === ',') {
options[0] = options[0].slice(0, -1);
}
if (words.includes(options[0]) || words.includes(options[1])) {
continue;
}
//First two elements are the flag and the third is the description
//Only autocomplete long
if (options.length > 1 && options[1].indexOf(next) === 0) {
l.push(options[1]);
} else if (options[0].indexOf(next) === 0) {
l.push(options[0]);
}
}
if (l.length === 0) {
return line;
}
let ret = l.map(a => toCommandLine(a));
ret.prefix = toCommandLine(words.slice(0, -1)) + ' ';
return ret;
}
//Complete an argument
//Determine the number of positional arguments by counting the number of
//words that don't start with a - less one for the command name
const positionalArgs = words.filter(a => a.indexOf('-') !== 0).length - 1;
let cmdUsage = yargParser(metadata.usage)['_'];
cmdUsage.splice(0, 1);
if (cmdUsage.length >= positionalArgs) {
let argName = cmdUsage[positionalArgs - 1];
argName = cliUtils.parseCommandArg(argName).name;
const currentFolder = app().currentFolder();
if (argName == 'note' || argName == 'note-pattern') {
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: next + '*' }) : [];
l.push(...notes.map(n => n.title));
}
if (argName == 'notebook') {
const folders = await Folder.search({ titlePattern: next + '*' });
l.push(...folders.map(n => n.title));
}
if (argName == 'item') {
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: next + '*' }) : [];
const folders = await Folder.search({ titlePattern: next + '*' });
l.push(...notes.map(n => n.title), folders.map(n => n.title));
}
if (argName == 'tag') {
let tags = await Tag.search({ titlePattern: next + '*' });
l.push(...tags.map(n => n.title));
}
if (argName == 'file') {
let files = await fs.readdir('.');
l.push(...files);
}
if (argName == 'tag-command') {
let c = filterList(['add', 'remove', 'list'], next);
l.push(...c);
}
if (argName == 'todo-command') {
let c = filterList(['toggle', 'clear'], next);
l.push(...c);
}
}
if (l.length === 1) {
return toCommandLine([...words.slice(0, -1), l[0]]);
} else if (l.length > 1) {
let ret = l.map(a => toCommandLine(a));
ret.prefix = toCommandLine(words.slice(0, -1)) + ' ';
return ret;
}
return line;
}
function handleAutocompletion(str, callback) {
handleAutocompletionPromise(str).then(function(res) {
callback(undefined, res);
});
}
function toCommandLine(args) {
if (Array.isArray(args)) {
return args
.map(function(a) {
if (a.indexOf('"') !== -1 || a.indexOf(' ') !== -1) {
return '\'' + a + '\'';
} else if (a.indexOf('\'') !== -1) {
return '"' + a + '"';
} else {
return a;
}
})
.join(' ');
} else {
if (args.indexOf('"') !== -1 || args.indexOf(' ') !== -1) {
return '\'' + args + '\' ';
} else if (args.indexOf('\'') !== -1) {
return '"' + args + '" ';
} else {
return args + ' ';
}
}
}
function getArguments(line) {
let inSingleQuotes = false;
let inDoubleQuotes = false;
let currentWord = '';
let parsed = [];
for (let i = 0; i < line.length; i++) {
if (line[i] === '"') {
if (inDoubleQuotes) {
inDoubleQuotes = false;
//maybe push word to parsed?
//currentWord += '"';
} else {
inDoubleQuotes = true;
//currentWord += '"';
}
} else if (line[i] === '\'') {
if (inSingleQuotes) {
inSingleQuotes = false;
//maybe push word to parsed?
//currentWord += "'";
} else {
inSingleQuotes = true;
//currentWord += "'";
}
} else if (/\s/.test(line[i]) && !(inDoubleQuotes || inSingleQuotes)) {
if (currentWord !== '') {
parsed.push(currentWord);
currentWord = '';
}
} else {
currentWord += line[i];
}
}
if (!(inSingleQuotes || inDoubleQuotes) && /\s/.test(line[line.length - 1])) {
parsed.push('');
} else {
parsed.push(currentWord);
}
return parsed;
}
function filterList(list, next) {
let output = [];
for (let i = 0; i < list.length; i++) {
if (list[i].indexOf(next) !== 0) continue;
output.push(list[i]);
}
return output;
}
module.exports = { handleAutocompletion };