make the command line ui process hints at least to a basic extent
This commit is contained in:
parent
b75e43962a
commit
1e65d71bde
12 changed files with 911 additions and 90 deletions
|
|
@ -113,7 +113,7 @@ var commands = {};
|
|||
* decoration to be done.
|
||||
* TODO: Are we sure that in the future there will be no such decoration?
|
||||
*/
|
||||
exports.addCommand = function(command) {
|
||||
function addCommand(command) {
|
||||
if (!command.name) {
|
||||
throw new Error('All registered commands must have a name');
|
||||
}
|
||||
|
|
@ -138,7 +138,7 @@ exports.addCommand = function(command) {
|
|||
commands[command.name] = command;
|
||||
};
|
||||
|
||||
exports.removeCommand = function(command) {
|
||||
function removeCommand(command) {
|
||||
if (typeof command === 'string') {
|
||||
delete commands[command];
|
||||
}
|
||||
|
|
@ -147,11 +147,11 @@ exports.removeCommand = function(command) {
|
|||
}
|
||||
};
|
||||
|
||||
exports.getCommand = function(name) {
|
||||
function getCommand(name) {
|
||||
return commands[name];
|
||||
};
|
||||
|
||||
exports.getCommandNames = function() {
|
||||
function getCommandNames() {
|
||||
return Object.keys(commands);
|
||||
};
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ exports.getCommandNames = function() {
|
|||
* everything it needs to about the command params
|
||||
* @param command Either a command, or the name of one
|
||||
*/
|
||||
exports.exec = function(command, args) {
|
||||
function exec(command, args) {
|
||||
if (typeof command === 'string') {
|
||||
command = commands[command];
|
||||
}
|
||||
|
|
@ -176,8 +176,15 @@ exports.exec = function(command, args) {
|
|||
return true;
|
||||
};
|
||||
|
||||
exports.removeCommand = removeCommand;
|
||||
exports.addCommand = addCommand;
|
||||
exports.getCommand = getCommand;
|
||||
exports.getCommandNames = getCommandNames;
|
||||
exports.exec = exec;
|
||||
|
||||
|
||||
/**
|
||||
* We publish a 'addedRequestOutput' event whenever new command begins output
|
||||
* We publish a 'output' event whenever new command begins output
|
||||
* TODO: make this more obvious
|
||||
*/
|
||||
oop.implement(exports, EventEmitter);
|
||||
|
|
@ -202,7 +209,7 @@ oop.implement(exports, EventEmitter);
|
|||
/**
|
||||
* The array of requests that wish to announce their presence
|
||||
*/
|
||||
exports.requests = [];
|
||||
var requests = [];
|
||||
|
||||
/**
|
||||
* How many requests do we store?
|
||||
|
|
@ -212,16 +219,17 @@ var maxRequestLength = 100;
|
|||
/**
|
||||
* Called by Request instances when some output (or a cell to async() happens)
|
||||
*/
|
||||
exports.addRequestOutput = function(request) {
|
||||
exports.requests.push(request);
|
||||
function addRequestOutput(request) {
|
||||
requests.push(request);
|
||||
// This could probably be optimized with some maths, but 99.99% of the
|
||||
// time we will only be off by one, and I'm feeling lazy.
|
||||
while (exports.requests.length > maxRequestLength) {
|
||||
exports.requests.shiftObject();
|
||||
while (requests.length > maxRequestLength) {
|
||||
requests.shiftObject();
|
||||
}
|
||||
|
||||
exports._dispatchEvent('addedRequestOutput', { request: request });
|
||||
exports._dispatchEvent('output', { requests: requests });
|
||||
};
|
||||
exports.addRequestOutput = addRequestOutput;
|
||||
|
||||
/**
|
||||
* To create an invocation, you need to do something like this (all the ctor
|
||||
|
|
|
|||
|
|
@ -61,24 +61,24 @@ var setCommandSpec = {
|
|||
// 'set' by itself lists all the settings
|
||||
var settingsList = env.settings._list();
|
||||
html = '';
|
||||
// first sort the settingsList based on the key
|
||||
// first sort the settingsList based on the name
|
||||
settingsList.sort(function(a, b) {
|
||||
if (a.key < b.key) {
|
||||
if (a.name < b.name) {
|
||||
return -1;
|
||||
} else if (a.key == b.key) {
|
||||
} else if (a.name == b.name) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
var url = 'https://wiki.mozilla.org/Labs/Skywriter/Settings#' +
|
||||
setting.key;
|
||||
settingsList.forEach(function(setting) {
|
||||
var url = 'https://wiki.mozilla.org/Labs/Skywriter/Settings#' +
|
||||
setting.name;
|
||||
html += '<a class="setting" href="' + url +
|
||||
'" title="View external documentation on setting: ' +
|
||||
setting.key +
|
||||
setting.name +
|
||||
'" target="_blank">' +
|
||||
setting.key +
|
||||
setting.name +
|
||||
'</a> = ' +
|
||||
setting.value +
|
||||
'<br/>';
|
||||
|
|
|
|||
406
plugins/pilot/lib/domtemplate.js
Normal file
406
plugins/pilot/lib/domtemplate.js
Normal file
|
|
@ -0,0 +1,406 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is DomTemplate.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Walker (jwalker@mozilla.com) (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
|
||||
// WARNING: do not 'use_strict' without reading the notes in envEval;
|
||||
|
||||
/**
|
||||
* A templater that allows one to quickly template DOM nodes.
|
||||
*/
|
||||
function Templater() {
|
||||
this.scope = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursive function to walk the tree processing the attributes as it goes.
|
||||
* @param node the node to process. If you pass a string in instead of a DOM
|
||||
* element, it is assumed to be an id for use with document.getElementById()
|
||||
* @param data the data to use for node processing.
|
||||
*/
|
||||
Templater.prototype.processNode = function(node, data) {
|
||||
if (typeof node === 'string') {
|
||||
node = document.getElementById(node);
|
||||
}
|
||||
if (data === null || data === undefined) {
|
||||
data = {};
|
||||
}
|
||||
this.scope.push(node.nodeName + (node.id ? '#' + node.id : ''));
|
||||
try {
|
||||
// Process attributes
|
||||
if (node.attributes && node.attributes.length) {
|
||||
// We need to handle 'foreach' and 'if' first because they might stop
|
||||
// some types of processing from happening, and foreach must come first
|
||||
// because it defines new data on which 'if' might depend.
|
||||
if (node.hasAttribute('foreach')) {
|
||||
this.processForEach(node, data);
|
||||
return;
|
||||
}
|
||||
if (node.hasAttribute('if')) {
|
||||
if (!this.processIf(node, data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Only make the node available once we know it's not going away
|
||||
data.__element = node;
|
||||
// It's good to clean up the attributes when we've processed them,
|
||||
// but if we do it straight away, we mess up the array index
|
||||
var attrs = Array.prototype.slice.call(node.attributes);
|
||||
for (var i = 0; i < attrs.length; i++) {
|
||||
var value = attrs[i].value;
|
||||
var name = attrs[i].name;
|
||||
this.scope.push(name);
|
||||
try {
|
||||
if (name === 'save') {
|
||||
// Save attributes are a setter using the node
|
||||
value = this.stripBraces(value);
|
||||
this.property(value, data, node);
|
||||
node.removeAttribute('save');
|
||||
} else if (name.substring(0, 2) === 'on') {
|
||||
// Event registration relies on property doing a bind
|
||||
value = this.stripBraces(value);
|
||||
var func = this.property(value, data);
|
||||
if (typeof func !== 'function') {
|
||||
this.handleError('Expected ' + value +
|
||||
' to resolve to a function, but got ' + typeof func);
|
||||
}
|
||||
node.removeAttribute(name);
|
||||
var capture = node.hasAttribute('capture' + name.substring(2));
|
||||
node.addEventListener(name.substring(2), func, capture);
|
||||
if (capture) {
|
||||
node.removeAttribute('capture' + name.substring(2));
|
||||
}
|
||||
} else {
|
||||
// Replace references in all other attributes
|
||||
var self = this;
|
||||
var newValue = value.replace(/\$\{[^}]*\}/g, function(path) {
|
||||
return self.envEval(path.slice(2, -1), data, value);
|
||||
});
|
||||
// Remove '_' prefix of attribute names so the DOM won't try
|
||||
// to use them before we've processed the template
|
||||
if (name.charAt(0) === '_') {
|
||||
node.removeAttribute(name);
|
||||
node.setAttribute(name.substring(1), newValue);
|
||||
} else if (value !== newValue) {
|
||||
attrs[i].value = newValue;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through our children calling processNode. First clone them, so the
|
||||
// set of nodes that we visit will be unaffected by additions or removals.
|
||||
var childNodes = Array.prototype.slice.call(node.childNodes);
|
||||
for (var j = 0; j < childNodes.length; j++) {
|
||||
this.processNode(childNodes[j], data);
|
||||
}
|
||||
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
this.processTextNode(node, data);
|
||||
}
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle <x if="${...}">
|
||||
* @param node An element with an 'if' attribute
|
||||
* @param data The data to use with envEval
|
||||
* @returns true if processing should continue, false otherwise
|
||||
*/
|
||||
Templater.prototype.processIf = function(node, data) {
|
||||
this.scope.push('if');
|
||||
try {
|
||||
var originalValue = node.getAttribute('if');
|
||||
var value = this.stripBraces(originalValue);
|
||||
var recurse = true;
|
||||
try {
|
||||
var reply = this.envEval(value, data, originalValue);
|
||||
recurse = !!reply;
|
||||
} catch (ex) {
|
||||
this.handleError('Error with \'' + value + '\'', ex);
|
||||
recurse = false;
|
||||
}
|
||||
if (!recurse) {
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
node.removeAttribute('if');
|
||||
return recurse;
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle <x foreach="param in ${array}"> and the special case of
|
||||
* <loop foreach="param in ${array}">
|
||||
* @param node An element with a 'foreach' attribute
|
||||
* @param data The data to use with envEval
|
||||
*/
|
||||
Templater.prototype.processForEach = function(node, data) {
|
||||
this.scope.push('foreach');
|
||||
try {
|
||||
var originalValue = node.getAttribute('foreach');
|
||||
var value = originalValue;
|
||||
|
||||
var paramName = 'param';
|
||||
if (value.charAt(0) === '$') {
|
||||
// No custom loop variable name. Use the default: 'param'
|
||||
value = this.stripBraces(value);
|
||||
} else {
|
||||
// Extract the loop variable name from 'NAME in ${ARRAY}'
|
||||
var nameArr = value.split(' in ');
|
||||
paramName = nameArr[0].trim();
|
||||
value = this.stripBraces(nameArr[1].trim());
|
||||
}
|
||||
node.removeAttribute('foreach');
|
||||
try {
|
||||
var self = this;
|
||||
// Process a single iteration of a loop
|
||||
var processSingle = function(member, clone, ref) {
|
||||
ref.parentNode.insertBefore(clone, ref);
|
||||
data[paramName] = member;
|
||||
self.processNode(clone, data);
|
||||
delete data[paramName];
|
||||
};
|
||||
|
||||
// processSingle is no good for <loop> nodes where we want to work on
|
||||
// the childNodes rather than the node itself
|
||||
var processAll = function(scope, member) {
|
||||
self.scope.push(scope);
|
||||
try {
|
||||
if (node.nodeName === 'LOOP') {
|
||||
for (var i = 0; i < node.childNodes.length; i++) {
|
||||
var clone = node.childNodes[i].cloneNode(true);
|
||||
processSingle(member, clone, node);
|
||||
}
|
||||
} else {
|
||||
var clone = node.cloneNode(true);
|
||||
clone.removeAttribute('foreach');
|
||||
processSingle(member, clone, node);
|
||||
}
|
||||
} finally {
|
||||
self.scope.pop();
|
||||
}
|
||||
};
|
||||
|
||||
var reply = this.envEval(value, data, originalValue);
|
||||
if (Array.isArray(reply)) {
|
||||
reply.forEach(function(data, i) {
|
||||
processAll('' + i, data);
|
||||
}, this);
|
||||
} else {
|
||||
for (var param in reply) {
|
||||
if (reply.hasOwnProperty(param)) {
|
||||
processAll(param, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
node.parentNode.removeChild(node);
|
||||
} catch (ex) {
|
||||
this.handleError('Error with \'' + value + '\'', ex);
|
||||
}
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Take a text node and replace it with another text node with the ${...}
|
||||
* sections parsed out. We replace the node by altering node.parentNode but
|
||||
* we could probably use a DOM Text API to achieve the same thing.
|
||||
* @param node The Text node to work on
|
||||
* @param data The data to use in calls to envEval
|
||||
*/
|
||||
Templater.prototype.processTextNode = function(node, data) {
|
||||
// Replace references in other attributes
|
||||
var value = node.data;
|
||||
// We can't use the string.replace() with function trick (see generic
|
||||
// attribute processing in processNode()) because we need to support
|
||||
// functions that return DOM nodes, so we can't have the conversion to a
|
||||
// string.
|
||||
// Instead we process the string as an array of parts. In order to split
|
||||
// the string up, we first replace '${' with '\uF001$' and '}' with '\uF002'
|
||||
// We can then split using \uF001 or \uF002 to get an array of strings
|
||||
// where scripts are prefixed with $.
|
||||
// \uF001 and \uF002 are just unicode chars reserved for private use.
|
||||
value = value.replace(/\$\{([^}]*)\}/g, '\uF001$$$1\uF002');
|
||||
var parts = value.split(/\uF001|\uF002/);
|
||||
if (parts.length > 1) {
|
||||
parts.forEach(function(part) {
|
||||
if (part === null || part === undefined || part === '') {
|
||||
return;
|
||||
}
|
||||
if (part.charAt(0) === '$') {
|
||||
part = this.envEval(part.slice(1), data, node.data);
|
||||
}
|
||||
// It looks like this was done a few lines above but see envEval
|
||||
if (part === null) {
|
||||
part = "null";
|
||||
}
|
||||
if (part === undefined) {
|
||||
part = "undefined";
|
||||
}
|
||||
// if (isDOMElement(part)) { ... }
|
||||
if (typeof part.cloneNode !== 'function') {
|
||||
part = node.ownerDocument.createTextNode(part.toString());
|
||||
}
|
||||
node.parentNode.insertBefore(part, node);
|
||||
}, this);
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Warn of string does not begin '${' and end '}'
|
||||
* @param str the string to check.
|
||||
* @return The string stripped of ${ and }, or untouched if it does not match
|
||||
*/
|
||||
Templater.prototype.stripBraces = function(str) {
|
||||
if (!str.match(/\$\{.*\}/g)) {
|
||||
this.handleError('Expected ' + str + ' to match ${...}');
|
||||
return str;
|
||||
}
|
||||
return str.slice(2, -1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Combined getter and setter that works with a path through some data set.
|
||||
* For example:
|
||||
* <ul>
|
||||
* <li>property('a.b', { a: { b: 99 }}); // returns 99
|
||||
* <li>property('a', { a: { b: 99 }}); // returns { b: 99 }
|
||||
* <li>property('a', { a: { b: 99 }}, 42); // returns 99 and alters the
|
||||
* input data to be { a: { b: 42 }}
|
||||
* </ul>
|
||||
* @param path An array of strings indicating the path through the data, or
|
||||
* a string to be cut into an array using <tt>split('.')</tt>
|
||||
* @param data An object to look in for the <tt>path</tt> argument
|
||||
* @param newValue (optional) If defined, this value will replace the
|
||||
* original value for the data at the path specified.
|
||||
* @return The value pointed to by <tt>path</tt> before any
|
||||
* <tt>newValue</tt> is applied.
|
||||
*/
|
||||
Templater.prototype.property = function(path, data, newValue) {
|
||||
this.scope.push(path);
|
||||
try {
|
||||
if (typeof path === 'string') {
|
||||
path = path.split('.');
|
||||
}
|
||||
var value = data[path[0]];
|
||||
if (path.length === 1) {
|
||||
if (newValue !== undefined) {
|
||||
data[path[0]] = newValue;
|
||||
}
|
||||
if (typeof value === 'function') {
|
||||
return function() {
|
||||
return value.apply(data, arguments);
|
||||
};
|
||||
}
|
||||
return value;
|
||||
}
|
||||
if (!value) {
|
||||
this.handleError('Can\'t find path=' + path);
|
||||
return null;
|
||||
}
|
||||
return this.property(path.slice(1), value, newValue);
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Like eval, but that creates a context of the variables in <tt>env</tt> in
|
||||
* which the script is evaluated.
|
||||
* WARNING: This script uses 'with' which is generally regarded to be evil.
|
||||
* The alternative is to create a Function at runtime that takes X parameters
|
||||
* according to the X keys in the env object, and then call that function using
|
||||
* the values in the env object. This is likely to be slow, but workable.
|
||||
* @param script The string to be evaluated.
|
||||
* @param env The environment in which to eval the script.
|
||||
* @param context Optional debugging string in case of failure
|
||||
* @return The return value of the script, or the error message if the script
|
||||
* execution failed.
|
||||
*/
|
||||
Templater.prototype.envEval = function(script, env, context) {
|
||||
with (env) {
|
||||
try {
|
||||
this.scope.push(context);
|
||||
return eval(script);
|
||||
} catch (ex) {
|
||||
this.handleError('Template error evaluating \'' + script + '\'', ex);
|
||||
return script;
|
||||
} finally {
|
||||
this.scope.pop();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A generic way of reporting errors, for easy overloading in different
|
||||
* environments.
|
||||
* @param message the error message to report.
|
||||
* @param ex optional associated exception.
|
||||
*/
|
||||
Templater.prototype.handleError = function(message, ex) {
|
||||
this.logError(message);
|
||||
this.logError('In: ' + this.scope.join(' > '));
|
||||
if (ex) {
|
||||
this.logError(ex);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A generic way of reporting errors, for easy overloading in different
|
||||
* environments.
|
||||
* @param message the error message to report.
|
||||
*/
|
||||
Templater.prototype.logError = function(message) {
|
||||
console.log(message);
|
||||
};
|
||||
|
||||
if (this.exports) {
|
||||
exports.Templater = Templater;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
|
@ -204,7 +204,7 @@ Settings.prototype = {
|
|||
resetAll: function() {
|
||||
this.getSettingNames().forEach(function(key) {
|
||||
this.resetValue(key);
|
||||
}.bind(this));
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -215,9 +215,9 @@ Settings.prototype = {
|
|||
this.getSettingNames().forEach(function(setting) {
|
||||
reply.push({
|
||||
'key': setting,
|
||||
'value': this.get(setting)
|
||||
'value': this.getSetting(setting).get()
|
||||
});
|
||||
}.bind(this));
|
||||
}, this);
|
||||
return reply;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -48,16 +48,21 @@ var Status = {
|
|||
* valid. There are a number of failure states, so the best way to check
|
||||
* for failure is (x !== Status.VALID)
|
||||
*/
|
||||
VALID: 'VALID',
|
||||
VALID: {
|
||||
toString: function() { return 'VALID'; },
|
||||
valueOf: function() { return 0; }
|
||||
},
|
||||
|
||||
/**
|
||||
* The conversion process did not work like Status.INVALID, however it was
|
||||
* noted that the string provided to 'parse()' could be VALID by the
|
||||
* addition of more characters, so the typing may not be actually incorrect
|
||||
* yet, just unfinished.
|
||||
* A conversion process failed, however it was noted that the string
|
||||
* provided to 'parse()' could be VALID by the addition of more characters,
|
||||
* so the typing may not be actually incorrect yet, just unfinished.
|
||||
* @see Status.INVALID
|
||||
*/
|
||||
INCOMPLETE: 'INCOMPLETE',
|
||||
INCOMPLETE: {
|
||||
toString: function() { return 'INCOMPLETE'; },
|
||||
valueOf: function() { return 1; }
|
||||
},
|
||||
|
||||
/**
|
||||
* The conversion process did not work, the value should be null and a
|
||||
|
|
@ -65,7 +70,10 @@ var Status = {
|
|||
* values may be available.
|
||||
* @see Status.INCOMPLETE
|
||||
*/
|
||||
INVALID: 'INVALID',
|
||||
INVALID: {
|
||||
toString: function() { return 'INVALID'; },
|
||||
valueOf: function() { return 2; }
|
||||
},
|
||||
|
||||
/**
|
||||
* A combined status is the worser of the provided statuses
|
||||
|
|
|
|||
|
|
@ -119,8 +119,8 @@ SelectionType.prototype.stringify = function(value) {
|
|||
return value;
|
||||
};
|
||||
|
||||
SelectionType.prototype.parse = function(value) {
|
||||
if (typeof value != 'string') {
|
||||
SelectionType.prototype.parse = function(str) {
|
||||
if (typeof str != 'string') {
|
||||
throw new Error('non-string passed to parse()');
|
||||
}
|
||||
if (!this.data) {
|
||||
|
|
@ -128,32 +128,40 @@ SelectionType.prototype.parse = function(value) {
|
|||
}
|
||||
var data = (typeof(this.data) === "function") ? this.data() : this.data;
|
||||
|
||||
var match = false;
|
||||
var match;
|
||||
var completions = [];
|
||||
data.forEach(function(option) {
|
||||
if (value == option) {
|
||||
match = true;
|
||||
if (str == option) {
|
||||
match = this.fromString(option);
|
||||
}
|
||||
else if (option.indexOf(value) === 0) {
|
||||
completions.push(option);
|
||||
else if (option.indexOf(str) === 0) {
|
||||
completions.push(this.fromString(option));
|
||||
}
|
||||
});
|
||||
}, this);
|
||||
|
||||
if (match) {
|
||||
return new Conversion(value);
|
||||
return new Conversion(match);
|
||||
}
|
||||
else {
|
||||
var status = completions.length > 0 ? Status.INCOMPLETE : Status.INVALID;
|
||||
|
||||
// TODO: better error message - include options?
|
||||
// TODO: better completions - we're just using the extensions
|
||||
return new Conversion(null,
|
||||
status,
|
||||
'Can\'t convert \'' + value + '\' to a selection.',
|
||||
completions);
|
||||
if (completions.length > 0) {
|
||||
return new Conversion(null,
|
||||
Status.INCOMPLETE,
|
||||
'Several possibilities for \'' + str + '\'',
|
||||
completions);
|
||||
}
|
||||
else {
|
||||
return new Conversion(null,
|
||||
Status.INVALID,
|
||||
'Can\'t use \'' + str + '\'.',
|
||||
completions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SelectionType.prototype.fromString = function(str) {
|
||||
return str;
|
||||
};
|
||||
|
||||
SelectionType.prototype.name = 'selection';
|
||||
|
||||
/**
|
||||
|
|
@ -170,17 +178,8 @@ var bool = new SelectionType({
|
|||
stringify: function(value) {
|
||||
return '' + value;
|
||||
},
|
||||
parse: function(value) {
|
||||
var conversion = SelectionType.prototype.parse(value);
|
||||
|
||||
if (conversion.value === 'true') {
|
||||
conversion.value = true;
|
||||
}
|
||||
if (conversion.value === 'false') {
|
||||
conversion.value = false;
|
||||
}
|
||||
|
||||
return conversion;
|
||||
fromString: function(str) {
|
||||
return str === 'true' ? true : false;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -54,15 +54,8 @@ var command = new SelectionType({
|
|||
stringify: function(command) {
|
||||
return command.name;
|
||||
},
|
||||
parse: function(value) {
|
||||
var conversion = SelectionType.prototype.parse.call(this, value);
|
||||
if (conversion.value) {
|
||||
conversion.value = canon.getCommand(conversion.value);
|
||||
}
|
||||
else {
|
||||
conversion.message = 'Several possibilities for \'' + value + '\'';
|
||||
}
|
||||
return conversion;
|
||||
fromString: function(str) {
|
||||
return canon.getCommand(str);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -63,17 +63,9 @@ var setting = new SelectionType({
|
|||
lastSetting = setting;
|
||||
return setting.name;
|
||||
},
|
||||
parse: function(text) {
|
||||
lastSetting = text;
|
||||
|
||||
var conversion = SelectionType.prototype.parse.call(this, text);
|
||||
if (conversion.value) {
|
||||
conversion.value = settings.getSetting(conversion.value);
|
||||
}
|
||||
else {
|
||||
conversion.message = 'Several possibilities for \'' + text + '\'';
|
||||
}
|
||||
return conversion;
|
||||
fromString: function(str) {
|
||||
lastSetting = settings.getSetting(str);
|
||||
return lastSetting;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -84,7 +76,7 @@ var setting = new SelectionType({
|
|||
var settingValue = new DeferredType({
|
||||
name: 'settingValue',
|
||||
defer: function() {
|
||||
return env.settings.getSetting(lastSetting).type;
|
||||
return lastSetting.type;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue