fune/devtools/shared/gcli/source/lib/gcli/commands/help.js

387 lines
12 KiB
JavaScript

/*
* Copyright 2012, Mozilla Foundation and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var l10n = require('../util/l10n');
var cli = require('../cli');
/**
* Add an 'paramGroups' accessor to a command metadata object to sort the
* params into groups according to the option of the param.
*/
function addParamGroups(command) {
Object.defineProperty(command, 'paramGroups', {
get: function() {
var paramGroups = {};
this.params.forEach(function(param) {
var groupName = param.option || l10n.lookup('canonDefaultGroupName');
if (paramGroups[groupName] == null) {
paramGroups[groupName] = [];
}
paramGroups[groupName].push(param);
});
return paramGroups;
},
enumerable: true
});
}
/**
* Get a data block for the help_man.html/help_man.txt templates
*/
function getHelpManData(commandData, context) {
// Filter out hidden parameters
commandData.command.params = commandData.command.params.filter(
param => !param.hidden
);
addParamGroups(commandData.command);
commandData.subcommands.forEach(addParamGroups);
return {
l10n: l10n.propertyLookup,
onclick: context.update,
ondblclick: context.updateExec,
describe: function(item) {
return item.manual || item.description;
},
getTypeDescription: function(param) {
var input = '';
if (param.defaultValue === undefined) {
input = l10n.lookup('helpManRequired');
}
else if (param.defaultValue === null) {
input = l10n.lookup('helpManOptional');
}
else {
// We need defaultText to work the text version of defaultValue
input = l10n.lookup('helpManOptional');
/*
var val = param.type.stringify(param.defaultValue);
input = Promise.resolve(val).then(function(defaultValue) {
return l10n.lookupFormat('helpManDefault', [ defaultValue ]);
}.bind(this));
*/
}
return Promise.resolve(input).then(defaultDescr => {
return '(' + (param.type.name || param.type) + ', ' + defaultDescr + ')';
});
},
getSynopsis: function(param) {
var name = param.name + (param.short ? '|-' + param.short : '');
if (param.option == null) {
return param.defaultValue !== undefined ?
'[' + name + ']' :
'<' + name + '>';
}
else {
return param.type === 'boolean' || param.type.name === 'boolean' ?
'[--' + name + ']' :
'[--' + name + ' ...]';
}
},
command: commandData.command,
subcommands: commandData.subcommands
};
}
/**
* Get a data block for the help_list.html/help_list.txt templates
*/
function getHelpListData(commandsData, context) {
commandsData.commands.forEach(addParamGroups);
var heading;
if (commandsData.commands.length === 0) {
heading = l10n.lookupFormat('helpListNone', [ commandsData.prefix ]);
}
else if (commandsData.prefix == null) {
heading = l10n.lookup('helpListAll');
}
else {
heading = l10n.lookupFormat('helpListPrefix', [ commandsData.prefix ]);
}
return {
l10n: l10n.propertyLookup,
includeIntro: commandsData.prefix == null,
heading: heading,
onclick: context.update,
ondblclick: context.updateExec,
matchingCommands: commandsData.commands
};
}
/**
* Create a block of data suitable to be passed to the help_list.html template
*/
function getMatchingCommands(context, prefix) {
var commands = cli.getMapping(context).requisition.system.commands;
var reply = commands.getAll().filter(function(command) {
if (command.hidden) {
return false;
}
if (prefix && command.name.indexOf(prefix) !== 0) {
// Filtered out because they don't match the search
return false;
}
if (!prefix && command.name.includes(' ')) {
// We don't show sub commands with plain 'help'
return false;
}
return true;
});
reply.sort(function(c1, c2) {
return c1.name.localeCompare(c2.name);
});
reply = reply.map(function(command) {
return command.toJson();
});
return reply;
}
/**
* Find all the sub commands of the given command
*/
function getSubCommands(context, command) {
var commands = cli.getMapping(context).requisition.system.commands;
var subcommands = commands.getAll().filter(function(subcommand) {
return subcommand.name.indexOf(command.name) === 0 &&
subcommand.name !== command.name &&
!subcommand.hidden;
});
subcommands.sort(function(c1, c2) {
return c1.name.localeCompare(c2.name);
});
subcommands = subcommands.map(function(subcommand) {
return subcommand.toJson();
});
return subcommands;
}
var helpCss = '' +
'.gcli-help-name {\n' +
' text-align: end;\n' +
'}\n' +
'\n' +
'.gcli-help-arrow {\n' +
' color: #AAA;\n' +
'}\n' +
'\n' +
'.gcli-help-description {\n' +
' margin: 0 20px;\n' +
' padding: 0;\n' +
'}\n' +
'\n' +
'.gcli-help-parameter {\n' +
' margin: 0 30px;\n' +
' padding: 0;\n' +
'}\n' +
'\n' +
'.gcli-help-header {\n' +
' margin: 10px 0 6px;\n' +
'}\n';
exports.items = [
{
// 'help' command
item: 'command',
name: 'help',
runAt: 'client',
description: l10n.lookup('helpDesc'),
manual: l10n.lookup('helpManual'),
params: [
{
name: 'search',
type: 'string',
description: l10n.lookup('helpSearchDesc'),
manual: l10n.lookup('helpSearchManual3'),
defaultValue: null
}
],
exec: function(args, context) {
var commands = cli.getMapping(context).requisition.system.commands;
var command = commands.get(args.search);
if (command) {
return context.typedData('commandData', {
command: command.toJson(),
subcommands: getSubCommands(context, command)
});
}
return context.typedData('commandsData', {
prefix: args.search,
commands: getMatchingCommands(context, args.search)
});
}
},
{
// Convert a command into an HTML man page
item: 'converter',
from: 'commandData',
to: 'view',
exec: function(commandData, context) {
return {
html:
'<div>\n' +
' <p class="gcli-help-header">\n' +
' ${l10n.helpManSynopsis}:\n' +
' <span class="gcli-out-shortcut" data-command="${command.name}"\n' +
' onclick="${onclick}" ondblclick="${ondblclick}">\n' +
' ${command.name}\n' +
' <span foreach="param in ${command.params}">${getSynopsis(param)} </span>\n' +
' </span>\n' +
' </p>\n' +
'\n' +
' <p class="gcli-help-description">${describe(command)}</p>\n' +
'\n' +
' <div if="${!command.isParent}">\n' +
' <div foreach="groupName in ${command.paramGroups}">\n' +
' <p class="gcli-help-header">${groupName}:</p>\n' +
' <ul class="gcli-help-parameter">\n' +
' <li if="${command.params.length === 0}">${l10n.helpManNone}</li>\n' +
' <li foreach="param in ${command.paramGroups[groupName]}">\n' +
' <code>${getSynopsis(param)}</code> <em>${getTypeDescription(param)}</em>\n' +
' <br/>\n' +
' ${describe(param)}\n' +
' </li>\n' +
' </ul>\n' +
' </div>\n' +
' </div>\n' +
'\n' +
' <div if="${command.isParent}">\n' +
' <p class="gcli-help-header">${l10n.subCommands}:</p>\n' +
' <ul class="gcli-help-${subcommands}">\n' +
' <li if="${subcommands.length === 0}">${l10n.subcommandsNone}</li>\n' +
' <li foreach="subcommand in ${subcommands}">\n' +
' ${subcommand.name}: ${subcommand.description}\n' +
' <span class="gcli-out-shortcut" data-command="help ${subcommand.name}"\n' +
' onclick="${onclick}" ondblclick="${ondblclick}">\n' +
' help ${subcommand.name}\n' +
' </span>\n' +
' </li>\n' +
' </ul>\n' +
' </div>\n' +
'\n' +
'</div>\n',
options: { allowEval: true, stack: 'commandData->view' },
data: getHelpManData(commandData, context),
css: helpCss,
cssId: 'gcli-help'
};
}
},
{
// Convert a command into a string based man page
item: 'converter',
from: 'commandData',
to: 'stringView',
exec: function(commandData, context) {
return {
html:
'<div>## ${command.name}\n' +
'\n' +
'# ${l10n.helpManSynopsis}: ${command.name} <loop foreach="param in ${command.params}">${getSynopsis(param)} </loop>\n' +
'\n' +
'# ${l10n.helpManDescription}:\n' +
'\n' +
'${command.manual || command.description}\n' +
'\n' +
'<loop foreach="groupName in ${command.paramGroups}">\n' +
'<span if="${!command.isParent}"># ${groupName}:\n' +
'\n' +
'<span if="${command.params.length === 0}">${l10n.helpManNone}</span><loop foreach="param in ${command.paramGroups[groupName]}">* ${param.name}: ${getTypeDescription(param)}\n' +
' ${param.manual || param.description}\n' +
'</loop>\n' +
'</span>\n' +
'</loop>\n' +
'\n' +
'<span if="${command.isParent}"># ${l10n.subCommands}:</span>\n' +
'\n' +
'<span if="${subcommands.length === 0}">${l10n.subcommandsNone}</span>\n' +
'<loop foreach="subcommand in ${subcommands}">* ${subcommand.name}: ${subcommand.description}\n' +
'</loop>\n' +
'</div>\n',
options: { allowEval: true, stack: 'commandData->stringView' },
data: getHelpManData(commandData, context)
};
}
},
{
// Convert a list of commands into a formatted list
item: 'converter',
from: 'commandsData',
to: 'view',
exec: function(commandsData, context) {
return {
html:
'<div>\n' +
' <div if="${includeIntro}">\n' +
' <p>${l10n.helpIntro}</p>\n' +
' </div>\n' +
'\n' +
' <p>${heading}</p>\n' +
'\n' +
' <table>\n' +
' <tr foreach="command in ${matchingCommands}">\n' +
' <td class="gcli-help-name">${command.name}</td>\n' +
' <td class="gcli-help-arrow">-</td>\n' +
' <td>\n' +
' ${command.description}\n' +
' <span class="gcli-out-shortcut"\n' +
' onclick="${onclick}" ondblclick="${ondblclick}"\n' +
' data-command="help ${command.name}">help ${command.name}</span>\n' +
' </td>\n' +
' </tr>\n' +
' </table>\n' +
'</div>\n',
options: { allowEval: true, stack: 'commandsData->view' },
data: getHelpListData(commandsData, context),
css: helpCss,
cssId: 'gcli-help'
};
}
},
{
// Convert a list of commands into a formatted list
item: 'converter',
from: 'commandsData',
to: 'stringView',
exec: function(commandsData, context) {
return {
html:
'<pre><span if="${includeIntro}">## ${l10n.helpIntro}</span>\n' +
'\n' +
'# ${heading}\n' +
'\n' +
'<loop foreach="command in ${matchingCommands}">${command.name} &#x2192; ${command.description}\n' +
'</loop></pre>',
options: { allowEval: true, stack: 'commandsData->stringView' },
data: getHelpListData(commandsData, context)
};
}
}
];