1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-27 10:32:58 +02:00
joplin/CliClient/app/autocompletion.js
2017-08-22 19:57:35 +02:00

175 lines
5.4 KiB
JavaScript

import { app } from './app.js';
import { Note } from 'lib/models/note.js';
import { Folder } from 'lib/models/folder.js';
import { Tag } from 'lib/models/tag.js';
import { cliUtils } from './cli-utils.js';
import { _ } from 'lib/locale.js';
import fs from 'fs-extra';
import os from 'os';
import yargParser from 'yargs-parser';
function autocompletionFileContent(appName, alias) {
let content = fs.readFileSync(__dirname + '/autocompletion_template.txt', 'utf8');
content = content.replace(/\|__APPNAME__\|/g, appName);
if (!alias) alias = 'joplin_alias_support_is_disabled';
content = content.replace(/\|__APPALIAS__\|/g, alias);
return content;
}
function autocompletionScriptPath(profileDir) {
return profileDir + '/autocompletion.sh';
}
async function installAutocompletionFile(appName, profileDir) {
if (process.env.SHELL.indexOf('bash') < 0) {
let error = new Error(_('Only Bash is currently supported for autocompletion.'));
error.code = 'shellNotSupported';
throw error;
}
const alias = await cliUtils.promptInput(_('Autocompletion can be made to work with an alias too (such as a one-letter command like "j").\nIf you would like to enable this, please type the alias now (leave it empty for no alias):'));
const content = autocompletionFileContent(appName, alias);
const filePath = autocompletionScriptPath(profileDir);
fs.writeFileSync(filePath, content);
console.info(_('Created autocompletion script "%s".', filePath));
const bashProfilePath = os.homedir() + '/.bashrc';
let bashrcContent = fs.readFileSync(bashProfilePath, 'utf8');
const lineToAdd = 'source ' + filePath;
if (bashrcContent.indexOf(lineToAdd) >= 0) {
console.info(_('Autocompletion script is already present in "%s".', bashProfilePath));
} else {
bashrcContent += "\n" + lineToAdd + "\n";
fs.writeFileSync(bashProfilePath, bashrcContent);
console.info(_('Added autocompletion to "%s".', bashProfilePath));
}
if (alias) {
if (bashrcContent.indexOf('alias ' + alias + '=') >= 0) {
console.info(_('Alias is already set in "%s".', bashProfilePath));
} else {
const l = 'alias ' + alias + '=' + appName;
bashrcContent += "\n" + l + "\n";
fs.writeFileSync(bashProfilePath, bashrcContent);
console.info(_('Added alias to "%s".', bashProfilePath));
}
}
console.info(_("IMPORTANT: run the following command to initialise autocompletion in the current shell:\nsource '%s'", filePath));
}
async function handleAutocompletion(autocompletion) {
let args = autocompletion.line.slice();
args.splice(0, 1);
let current = autocompletion.current - 1;
const currentWord = args[current] ? args[current] : '';
// Auto-complete the command name
if (current == 0) {
const metadata = await app().commandMetadata();
let commandNames = [];
for (let n in metadata) {
if (!metadata.hasOwnProperty(n)) continue;
const md = metadata[n];
if (md.hidden) continue;
if (currentWord == n) return [n];
if (n.indexOf(currentWord) === 0) commandNames.push(n);
}
return commandNames;
}
const commandName = args[0];
const metadata = await app().commandMetadata();
const md = metadata[commandName];
const options = md && md.options ? md.options : [];
// Auto-complete the command options
if (currentWord) {
const includeLongs = currentWord.length == 1 ? currentWord.substr(0, 1) == '-' : currentWord.substr(0, 2) == '--';
const includeShorts = currentWord.length <= 2 && currentWord.substr(0, 1) == '-' && currentWord.substr(0, 2) != '--';
if (includeLongs || includeShorts) {
const output = [];
for (let i = 0; i < options.length; i++) {
const flags = cliUtils.parseFlags(options[i][0]);
const long = flags.long ? '--' + flags.long : null;
const short = flags.short ? '-' + flags.short : null;
if (includeLongs && long && long.indexOf(currentWord) === 0) output.push(long);
if (includeShorts && short && short.indexOf(currentWord) === 0) output.push(short);
}
return output;
}
}
// Auto-complete the command arguments
let argIndex = -1;
for (let i = 0; i < args.length; i++) {
const w = args[i];
if (i == 0 || w.indexOf('-') == 0) {
continue;
}
argIndex++;
}
if (argIndex < 0) return [];
let cmdUsage = yargParser(md.usage)['_'];
cmdUsage.splice(0, 1);
if (cmdUsage.length <= argIndex) return [];
let argName = cmdUsage[argIndex];
argName = cliUtils.parseCommandArg(argName).name;
if (argName == 'note' || argName == 'note-pattern') {
if (!app().currentFolder()) return [];
const notes = await Note.previews(app().currentFolder().id, { titlePattern: currentWord + '*' });
return notes.map((n) => n.title);
}
if (argName == 'notebook') {
const folders = await Folder.search({ titlePattern: currentWord + '*' });
return folders.map((n) => n.title);
}
if (argName == 'tag') {
let tags = await Tag.search({ titlePattern: currentWord + '*' });
return tags.map((n) => n.title);
}
if (argName == 'tag-command') {
return filterList(['add', 'remove', 'list'], currentWord);
}
if (argName == 'todo-command') {
return filterList(['toggle', 'clear'], currentWord);
}
if (argName == 'command') {
const commands = await app().commandNames();
return this.filterList(commands, currentWord);
}
return [];
}
function filterList(list, currentWord) {
let output = [];
for (let i = 0; i < list.length; i++) {
if (list[i].indexOf(currentWord) !== 0) continue;
output.push(list[i]);
}
return output;
}
export { handleAutocompletion, installAutocompletionFile, autocompletionScriptPath };