// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2008-2014 by Kris Maglione <maglione.k@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
try {
-Components.utils.import("resource://dactyl/bootstrap.jsm");
defineModule("options", {
exports: ["Option", "Options", "ValueError", "options"],
- require: ["messages", "storage"],
- use: ["commands", "completion", "config", "prefs", "services", "styles", "template", "util"]
-}, this);
+ require: ["contexts", "messages", "storage"]
+});
+
+lazyRequire("cache", ["cache"]);
+lazyRequire("config", ["config"]);
+lazyRequire("commands", ["Commands"]);
+lazyRequire("completion", ["CompletionContext"]);
+lazyRequire("prefs", ["prefs"]);
+lazyRequire("styles", ["Styles"]);
+lazyRequire("template", ["template"]);
/** @scope modules */
init: function init(modules, names, description, defaultValue, extraInfo) {
this.modules = modules;
this.name = names[0];
- this.names = names;
this.realNames = names;
this.description = description;
if (extraInfo)
this.update(extraInfo);
- if (Set.has(this.modules.config.defaults, this.name))
- defaultValue = this.modules.config.defaults[this.name];
-
- if (defaultValue !== undefined) {
- if (this.type === "string")
- defaultValue = Commands.quote(defaultValue);
-
- if (isObject(defaultValue))
- defaultValue = iter(defaultValue).map(function (val) val.map(Option.quote).join(":")).join(",");
-
- if (isArray(defaultValue))
- defaultValue = defaultValue.map(Option.quote).join(",");
-
- this.defaultValue = this.parse(defaultValue);
- }
-
- // add no{option} variant of boolean {option} to this.names
- if (this.type == "boolean")
- this.names = array([name, "no" + name] for (name in values(names))).flatten().array;
+ this._defaultValue = defaultValue;
if (this.globalValue == undefined && !this.initialValue)
this.globalValue = this.defaultValue;
},
- magicalProperties: Set(["cleanupValue"]),
+ magicalProperties: RealSet(["cleanupValue"]),
/**
* @property {string} This option's description, as shown in :listoptions.
get helpTag() "'" + this.name + "'",
initValue: function initValue() {
- util.trapErrors(function () this.value = this.value, this);
+ util.trapErrors(() => { this.value = this.value; });
},
get isDefault() this.stringValue === this.stringDefaultValue,
},
/** @property {value} The option's global value. @see #scope */
- get globalValue() { try { return options.store.get(this.name, {}).value; } catch (e) { util.reportError(e); throw e; } },
- set globalValue(val) { options.store.set(this.name, { value: val, time: Date.now() }); },
+ get globalValue() {
+ let val = options.store.get(this.name, {}).value;
+ if (val != null)
+ return val;
+ return this.globalValue = this.defaultValue;
+ },
+ set globalValue(val) {
+ options.store.set(this.name,
+ { value: this.parse(this.stringify(val)),
+ time: Date.now() });
+ },
/**
* Returns *value* as an array of parsed values if the option type is
*/
parse: function parse(value) Option.dequote(value),
+ parseKey: function parseKey(value) value,
+
/**
* Returns *values* packed in the appropriate format for the option type.
*
if ((scope & Option.SCOPE_GLOBAL) && (values == undefined))
values = this.globalValue;
+ if (hasOwnProperty(this, "_value"))
+ values = this._value;
+
if (this.getter)
return util.trapErrors(this.getter, this, values);
*/
if ((scope & Option.SCOPE_GLOBAL) && !skipGlobal)
this.globalValue = newValues;
+ this._value = newValues;
this.hasChanged = true;
this.setFrom = null;
*
* @returns {boolean}
*/
- has: function has() Array.some(arguments, function (val) this.value.indexOf(val) >= 0, this),
+ has: function has() Array.some(arguments, val => this.value.indexOf(val) >= 0),
/**
* Returns whether this option is identified by *name*.
return null;
},
- // Properties {{{2
+ // Properties {{{
/** @property {string} The option's canonical name. */
name: null,
+
/** @property {[string]} All names by which this option is identified. */
- names: null,
+ names: Class.Memoize(function () this.realNames),
/**
* @property {string} The option's data type. One of:
* references to a given domain from the given values.
*/
filterDomain: function filterDomain(host, values)
- Array.filter(values, function (val) !this.domains([val]).some(function (val) util.isSubdomain(val, host)), this),
+ Array.filter(values, val => !this.domains([val]).some(val => util.isSubdomain(val, host))),
/**
* @property {value} The option's default value. This value will be used
* unless the option is explicitly set either interactively or in an RC
* file or plugin.
*/
- defaultValue: null,
+ defaultValue: Class.Memoize(function () {
+ let defaultValue = this._defaultValue;
+ delete this._defaultValue;
+
+ if (hasOwnProperty(this.modules.config.optionDefaults, this.name))
+ defaultValue = this.modules.config.optionDefaults[this.name];
+
+ if (defaultValue == null && this.getter)
+ defaultValue = this.getter();
+
+ if (defaultValue == undefined)
+ return null;
+
+ if (this.type === "string")
+ defaultValue = Commands.quote(defaultValue);
+
+ if (isArray(defaultValue))
+ defaultValue = defaultValue.map(Option.quote).join(",");
+ else if (isObject(defaultValue))
+ defaultValue = iter(defaultValue).map(val => val.map(v => Option.quote(v, /:/))
+ .join(":"))
+ .join(",");
+
+ if (isArray(defaultValue))
+ defaultValue = defaultValue.map(Option.quote).join(",");
+
+ return this.parse(defaultValue);
+ }),
/**
* @property {function} The function called when the option value is read.
hasChanged: false,
/**
- * Returns the timestamp when the option's value was last changed.
+ * @property {number} Returns the timestamp when the option's value was
+ * last changed.
*/
get lastSet() options.store.get(this.name).time,
set lastSet(val) { options.store.set(this.name, { value: this.globalValue, time: Date.now() }); },
*/
setFrom: null
+ //}}}
}, {
/**
* @property {number} Global option scope.
let re = util.regexp(Option.dequote(val), flags);
re.bang = bang;
re.result = result !== undefined ? result : !bang;
+ re.key = re.bang + Option.quote(util.regexp.getSource(re), /^!|:/);
re.toString = function () Option.unparseRegexp(this, keepQuotes);
return re;
},
unparseRegexp: function unparseRegexp(re, quoted) re.bang + Option.quote(util.regexp.getSource(re), /^!|:/) +
- (typeof re.result === "boolean" ? "" : ":" + (quoted ? re.result : Option.quote(re.result))),
+ (typeof re.result === "boolean" ? "" : ":" + (quoted ? re.result : Option.quote(re.result, /:/))),
parseSite: function parseSite(pattern, result, rest) {
if (isArray(rest)) // Called by Array.map
result = undefined;
let [, bang, filter] = /^(!?)(.*)/.exec(pattern);
- filter = Option.dequote(filter);
+ filter = Option.dequote(filter).trim();
- let quote = this.keepQuotes ? util.identity : Option.quote;
+ let quote = this.keepQuotes ? v => v
+ : v => Option.quote(v, /:/);
return update(Styles.matchFilter(filter), {
bang: bang,
stringlist: function stringlist(k) this.value.indexOf(k) >= 0,
get charlist() this.stringlist,
- regexplist: function regexplist(k, default_) {
+ regexplist: function regexplist(k, default_=null) {
for (let re in values(this.value))
if ((re.test || re).call(re, k))
return re.result;
- return arguments.length > 1 ? default_ : null;
+ return default_;
},
get regexpmap() this.regexplist,
get sitelist() this.regexplist,
},
domains: {
- sitelist: function (vals) array.compact(vals.map(function (site) util.getHost(site.filter))),
+ sitelist: function (vals) array.compact(vals.map(site => util.getHost(site.filter))),
get sitemap() this.sitelist
},
stringlist: function (vals) vals.map(Option.quote).join(","),
- stringmap: function (vals) [Option.quote(k, /:/) + ":" + Option.quote(v) for ([k, v] in Iterator(vals))].join(","),
+ stringmap: function (vals) [Option.quote(k, /:/) + ":" + Option.quote(v, /:/) for ([k, v] in Iterator(vals))].join(","),
regexplist: function (vals) vals.join(","),
get regexpmap() this.regexplist,
regexplist: function regexplist(value) (value === "") ? [] :
Option.splitList(value, true)
- .map(function (re) Option.parseRegexp(re, undefined, this.regexpFlags), this),
+ .map(re => Option.parseRegexp(re, undefined, this.regexpFlags)),
sitelist: function sitelist(value) {
if (value === "")
}, this))
},
+ parseKey: {
+ number: Number,
+ boolean: function boolean(value) value == "true" || value == true ? true : false,
+ },
+
testValues: {
- regexpmap: function regexpmap(vals, validator) vals.every(function (re) validator(re.result)),
+ regexpmap: function regexpmap(vals, validator) vals.every(re => validator(re.result)),
get sitemap() this.regexpmap,
stringlist: function stringlist(vals, validator) vals.every(validator, this),
stringmap: function stringmap(vals, validator) values(vals).every(validator, this)
return res;
},
- quote: function quote(str, re) isArray(str) ? str.map(function (s) quote(s, re)).join(",") :
+ quote: function quote(str, re) isArray(str) ? str.map(s => quote(s, re)).join(",") :
Commands.quoteArg[/[\s|"'\\,]|^$/.test(str) || re && re.test && re.test(str)
? (/[\b\f\n\r\t]/.test(str) ? '"' : "'")
: ""](str, re),
return null;
},
+ string: function string(operator, values, scope, invert) {
+ if (invert)
+ return values[(values.indexOf(this.value) + 1) % values.length];
+
+ switch (operator) {
+ case "+":
+ return this.value + values;
+ case "-":
+ return this.value.replace(values, "");
+ case "^":
+ return values + this.value;
+ case "=":
+ return values;
+ }
+ return null;
+ },
+
stringmap: function stringmap(operator, values, scope, invert) {
let res = update({}, this.value);
values = Array.concat(values);
function uniq(ary) {
- let seen = {};
- return ary.filter(function (elem) !Set.add(seen, elem));
+ let seen = RealSet();
+ return ary.filter(elem => !seen.add(elem));
}
switch (operator) {
// NOTE: Vim doesn't prepend if there's a match in the current value
return uniq(Array.concat(values, this.value), true);
case "-":
- return this.value.filter(function (item) !Set.has(this, item), Set(values));
+ return this.value.filter(function (item) !this.has(item), RealSet(values));
case "=":
if (invert) {
- let keepValues = this.value.filter(function (item) !Set.has(this, item), Set(values));
- let addValues = values.filter(function (item) !Set.has(this, item), Set(this.value));
+ let keepValues = this.value.filter(function (item) !this.has(item), RealSet(values));
+ let addValues = values.filter(function (item) !this.has(item), RealSet(this.value));
return addValues.concat(keepValues);
}
return values;
get regexplist() this.stringlist,
get regexpmap() this.stringlist,
get sitelist() this.stringlist,
- get sitemap() this.stringlist,
-
- string: function string(operator, values, scope, invert) {
- if (invert)
- return values[(values.indexOf(this.value) + 1) % values.length];
- switch (operator) {
- case "+":
- return this.value + values;
- case "-":
- return this.value.replace(values, "");
- case "^":
- return values + this.value;
- case "=":
- return values;
- }
- return null;
- }
+ get sitemap() this.stringlist
},
validIf: function validIf(test, error) {
* @param {value|[string]} values The value or array of values to validate.
* @returns {boolean}
*/
- validateCompleter: function validateCompleter(values) {
- if (this.values)
- var acceptable = this.values.array || this.values;
- else {
+ validateCompleter: function validateCompleter(vals) {
+ function completions(extra) {
let context = CompletionContext("");
- acceptable = context.fork("", 0, this, this.completer);
- if (!acceptable)
- acceptable = context.allItems.items.map(function (item) [item.text]);
+ return context.fork("", 0, this, this.completer, extra) ||
+ context.allItems.items.map(item => [item.text]);
+ };
+
+ if (isObject(vals) && !isArray(vals)) {
+ let k = values(completions.call(this, { values: {} })).toObject();
+ let v = values(completions.call(this, { value: "" })).toObject();
+
+ return Object.keys(vals).every(hasOwnProperty.bind(null, k)) &&
+ values(vals).every(hasOwnProperty.bind(null, v));
}
+ if (this.values)
+ var acceptable = this.values.array || this.values;
+ else
+ acceptable = completions.call(this);
+
if (isArray(acceptable))
- acceptable = Set(acceptable.map(function ([k]) k));
+ acceptable = RealSet(acceptable.map(([k]) => k));
+ else
+ acceptable = RealSet(this.parseKey(k)
+ for (k of Object.keys(acceptable)));
if (this.type === "regexpmap" || this.type === "sitemap")
- return Array.concat(values).every(function (re) Set.has(acceptable, re.result));
+ return Array.concat(vals).every(re => acceptable.has(re.result));
- return Array.concat(values).every(Set.has(acceptable));
+ return Array.concat(vals).every(v => acceptable.has(v));
},
types: {}
if (type in Option.parse)
class_.prototype.parse = Option.parse[type];
+ if (type in Option.parseKey)
+ class_.prototype.parseKey = Option.parse[type];
+
if (type in Option.stringify)
class_.prototype.stringify = Option.stringify[type];
EXPORTED_SYMBOLS.push(class_.className);
}, this);
+update(BooleanOption.prototype, {
+ names: Class.Memoize(function ()
+ array.flatten([[name, "no" + name] for (name in values(this.realNames))]))
+});
+
+var OptionHive = Class("OptionHive", Contexts.Hive, {
+ init: function init(group) {
+ init.supercall(this, group);
+ this.values = {};
+ this.has = v => hasOwnProperty(this.values, v);
+ },
+
+ add: function add(names, description, type, defaultValue, extraInfo) {
+ return this.modules.options.add(names, description, type, defaultValue, extraInfo);
+ }
+});
+
/**
* @instance options
*/
Local: function Local(dactyl, modules, window) let ({ contexts } = modules) ({
init: function init() {
const self = this;
+
+ update(this, {
+ hives: contexts.Hives("options", Class("OptionHive", OptionHive, { modules: modules })),
+ user: contexts.hives.options.user
+ });
+
this.needInit = [];
this._options = [];
this._optionMap = {};
opt.set(opt.globalValue, Option.SCOPE_GLOBAL, true);
}, window);
- services["dactyl:"].pages["options.dtd"] = function () [null,
- util.makeDTD(
- iter(([["option", o.name, "default"].join("."),
- o.type === "string" ? o.defaultValue.replace(/'/g, "''") :
- o.value === true ? "on" :
- o.value === false ? "off" : o.stringDefaultValue]
- for (o in self)),
+ modules.cache.register("options.dtd",
+ () => util.makeDTD(
+ iter(([["option", o.name, "default"].join("."),
+ o.type === "string" ? o.defaultValue.replace(/'/g, "''") :
+ o.defaultValue === true ? "on" :
+ o.defaultValue === false ? "off" : o.stringDefaultValue]
+ for (o in self)),
- ([["option", o.name, "type"].join("."), o.type] for (o in self)),
+ ([["option", o.name, "type"].join("."), o.type] for (o in self)),
- config.dtd))];
+ config.dtd)),
+ true);
+ },
+
+ signals: {
+ "io.source": function ioSource(context, file, modTime) {
+ cache.flushEntry("options.dtd", modTime);
+ }
},
dactyl: dactyl,
function opts(opt) {
for (let opt in Iterator(this)) {
+ if (filter && !filter(opt))
+ continue;
+ if (!(opt.scope & scope))
+ continue;
+
let option = {
__proto__: opt,
isDefault: opt.isDefault,
default: opt.stringDefaultValue,
pre: "\u00a0\u00a0", // Unicode nonbreaking space.
- value: <></>
+ value: []
};
- if (filter && !filter(opt))
- continue;
- if (!(opt.scope & scope))
- continue;
-
if (opt.type == "boolean") {
if (!opt.value)
option.pre = "no";
option.default = (opt.defaultValue ? "" : "no") + opt.name;
}
- else if (isArray(opt.value))
- option.value = <>={template.map(opt.value, function (v) template.highlight(String(v)), <>,<span style="width: 0; display: inline-block"> </span></>)}</>;
+ else if (isArray(opt.value) && opt.type != "charlist")
+ option.value = ["", "=",
+ template.map(opt.value,
+ v => template.highlight(String(v)),
+ ["", ",",
+ ["span", { style: "width: 0; display: inline-block" }, " "]])];
else
- option.value = <>={template.highlight(opt.stringValue)}</>;
+ option.value = ["", "=", template.highlight(opt.stringValue)];
yield option;
}
};
- modules.commandline.commandOutput(template.options("Options", opts.call(this), this["verbose"] > 0));
+ modules.commandline.commandOutput(
+ template.options("Options", opts.call(this), this["verbose"] > 0));
},
cleanup: function cleanup() {
* @optional
*/
add: function add(names, description, type, defaultValue, extraInfo) {
- const self = this;
+ if (!util.isDactyl(Components.stack.caller))
+ deprecated.warn(add, "options.add", "group.options.add");
+
+ util.assert(type in Option.types, _("option.noSuchType", type),
+ false);
if (!extraInfo)
extraInfo = {};
this.remove(name);
}
- let closure = function () self._optionMap[name];
+ let closure = () => this._optionMap[name];
+
+ memoize(this._optionMap, name,
+ function () Option.types[type](modules, names, description, defaultValue, extraInfo));
- memoize(this._optionMap, name, function () Option.types[type](modules, names, description, defaultValue, extraInfo));
for (let alias in values(names.slice(1)))
memoize(this._optionMap, alias, closure);
/** @property {Iterator(Option)} @private */
__iterator__: function __iterator__()
- values(this._options.sort(function (a, b) String.localeCompare(a.name, b.name))),
+ values(this._options.sort((a, b) => String.localeCompare(a.name, b.name))),
allPrefs: deprecated("prefs.getNames", function allPrefs() prefs.getNames.apply(prefs, arguments)),
getPref: deprecated("prefs.get", function getPref() prefs.get.apply(prefs, arguments)),
setPref: deprecated("prefs.set", function setPref() prefs.set.apply(prefs, arguments)),
withContext: deprecated("prefs.withContext", function withContext() prefs.withContext.apply(prefs, arguments)),
- cleanupPrefs: Class.memoize(function () localPrefs.Branch("cleanup.option.")),
+ cleanupPrefs: Class.Memoize(() => config.prefs.Branch("cleanup.option.")),
cleanup: function cleanup(reason) {
if (~["disable", "uninstall"].indexOf(reason))
res.optionValue = res.option.get(res.scope);
try {
- res.values = res.option.parse(res.value);
+ if (!res.invert || res.option.type != "number") // Hack.
+ res.values = res.option.parse(res.value);
}
catch (e) {
res.error = e;
*/
remove: function remove(name) {
let opt = this.get(name);
- this._options = this._options.filter(function (o) o != opt);
+ this._options = this._options.filter(o => o != opt);
for (let name in values(opt.names))
delete this._optionMap[name];
},
commands: function initCommands(dactyl, modules, window) {
const { commands, contexts, options } = modules;
- let args = {
- getMode: function (args) findMode(args["-mode"]),
- iterate: function (args) {
- for (let map in mappings.iterate(this.getMode(args)))
- for (let name in values(map.names))
- yield { name: name, __proto__: map };
- },
- format: {
- description: function (map) (XML.ignoreWhitespace = false, XML.prettyPrinting = false, <>
- {options.get("passkeys").has(map.name)
- ? <span highlight="URLExtra">({
- tempate.linkifyHelp(_("option.passkeys.passedBy"))
- })</span>
- : <></>}
- {template.linkifyHelp(map.description)}
- </>)
- }
- };
-
dactyl.addUsageCommand({
name: ["listo[ptions]", "lo"],
description: "List all options along with their short descriptions",
index: "option",
iterate: function (args) options,
format: {
- description: function (opt) (XML.ignoreWhitespace = false, XML.prettyPrinting = false, <>
- {opt.scope == Option.SCOPE_LOCAL
- ? <span highlight="URLExtra">({_("option.bufferLocal")})</span> : ""}
- {template.linkifyHelp(opt.description)}
- </>),
+ description: function (opt) [
+ opt.scope == Option.SCOPE_LOCAL
+ ? ["span", { highlight: "URLExtra" },
+ "(" + _("option.bufferLocal") + ")"]
+ : "",
+ template.linkifyHelp(opt.description)
+ ],
help: function (opt) "'" + opt.name + "'"
}
});
let list = [];
function flushList() {
- let names = Set(list.map(function (opt) opt.option ? opt.option.name : ""));
+ let names = RealSet(list.map(opt => opt.option ? opt.option.name : ""));
if (list.length)
- if (list.some(function (opt) opt.all))
- options.list(function (opt) !(list[0].onlyNonDefault && opt.isDefault), list[0].scope);
+ if (list.some(opt => opt.all))
+ options.list(opt => !(list[0].onlyNonDefault && opt.isDefault),
+ list[0].scope);
else
- options.list(function (opt) Set.has(names, opt.name), list[0].scope);
+ options.list(opt => names.has(opt.name),
+ list[0].scope);
list = [];
}
}
else {
var [matches, name, postfix, valueGiven, operator, value] =
- arg.match(/^\s*?([^=]+?)([?&!])?\s*(([-+^]?)=(.*))?\s*$/);
+ arg.match(/^\s*?((?:[^=\\']|\\.|'[^']*')+?)([?&!])?\s*(([-+^]?)=(.*))?\s*$/);
reset = (postfix == "&");
invertBoolean = (postfix == "!");
}
+ name = Option.dequote(name);
if (name == "all" && reset)
modules.commandline.input(_("pref.prompt.resetAll", config.host) + " ",
function (resp) {
context.advance(filter.length);
filter = filter.substr(0, filter.length - 1);
- context.pushProcessor(0, function (item, text, next) next(item, text.substr(0, 100)));
+ context.pushProcessor(0, (item, text, next) => next(item, text.substr(0, 100)));
context.completions = [
[prefs.get(filter), _("option.currentValue")],
[prefs.defaults.get(filter), _("option.defaultValue")]
- ].filter(function (k) k[0] != null);
+ ].filter(k => k[0] != null);
return null;
}
context.highlight();
if (context.filter.indexOf("=") == -1) {
if (false && prefix)
- context.filters.push(function ({ item }) item.type == "boolean" || prefix == "inv" && isArray(item.values));
- return completion.option(context, opt.scope, opt.name == "inv" ? opt.name : prefix);
+ context.filters.push(({ item }) => (item.type == "boolean" ||
+ prefix == "inv" && isArray(item.values)));
+
+ return completion.option(context, opt.scope,
+ opt.name == "inv" ? opt.name
+ : prefix);
}
function error(length, message) {
if (!opt.value && !opt.operator && !opt.invert) {
context.fork("default", 0, this, function (context) {
context.title = ["Extra Completions"];
- context.pushProcessor(0, function (item, text, next) next(item, text.substr(0, 100)));
+ context.pushProcessor(0, (item, text, next) => next(item, text.substr(0, 100)));
context.completions = [
[option.stringValue, _("option.currentValue")],
[option.stringDefaultValue, _("option.defaultValue")]
- ].filter(function (f) f[0] !== "");
+ ].filter(f => f[0] !== "");
context.quote = ["", util.identity, ""];
});
}
// Fill in the current values if we're removing
if (opt.operator == "-" && isArray(opt.values)) {
- let have = Set([i.text for (i in values(context.allItems.items))]);
+ let have = RealSet((i.text for (i in values(context.allItems.items))));
context = context.fork("current-values", 0);
context.anchored = optcontext.anchored;
context.maxItems = optcontext.maxItems;
- context.filters.push(function (i) !Set.has(have, i.text));
+ context.filters.push(i => !have.has(i.text));
modules.completion.optionValue(context, opt.name, opt.operator, null,
function (context) {
- context.generate = function () option.value.map(function (o) [o, ""]);
+ context.generate = () => option.value.map(o => [o, ""]);
});
context.title = ["Current values"];
}
function fmt(value) (typeof value == "number" ? "#" :
typeof value == "function" ? "*" :
" ") + value;
- if (!args || args == "g:") {
- let str =
- <table>
- {
- template.map(globalVariables, function ([i, value]) {
- return <tr>
- <td style="width: 200px;">{i}</td>
- <td>{fmt(value)}</td>
- </tr>;
- })
- }
- </table>;
- if (str.text().length() == str.*.length())
- dactyl.echomsg(_("variable.none"));
- else
- dactyl.echo(str, modules.commandline.FORCE_MULTILINE);
- return;
- }
+ util.assert(!(!args || args == "g:"));
let matches = args.match(/^([a-z]:)?([\w]+)(?:\s*([-+.])?=\s*(.*)?)?$/);
if (matches) {
util.assert(scope == "g:" || scope == null,
_("command.let.illegalVar", scope + name));
- util.assert(Set.has(globalVariables, name) || (expr && !op),
+ util.assert(hasOwnProperty(globalVariables, name) || (expr && !op),
_("command.let.undefinedVar", fullName));
if (!expr)
function (args) {
for (let [, name] in args) {
name = name.replace(/^g:/, ""); // throw away the scope prefix
- if (!Set.has(dactyl._globalVariables, name)) {
+ if (!hasOwnProperty(dactyl._globalVariables, name)) {
if (!args.bang)
dactyl.echoerr(_("command.let.noSuch", name));
return;
context.anchored = false;
context.completions = modules.options;
if (prefix == "inv")
- context.keys.text = function (opt)
- opt.type == "boolean" || isArray(opt.value) ? opt.names.map(function (n) "inv" + n)
+ context.keys.text = opt =>
+ opt.type == "boolean" || isArray(opt.value) ? opt.names.map(n => "inv" + n)
: opt.names;
if (scope)
- context.filters.push(function ({ item }) item.scope & scope);
+ context.filters.push(({ item }) => item.scope & scope);
};
completion.optionValue = function (context, name, op, curValue, completer) {
context.advance(Option._splitAt);
context.filter = Option.dequote(context.filter);
+ function val(obj) {
+ if (isArray(opt.defaultValue)) {
+ let val = [].find.call(obj, re => (re.key == extra.key));
+ return val && val.result;
+ }
+ if (hasOwnProperty(opt.defaultValue, extra.key))
+ return obj[extra.key];
+ }
+
+ if (extra.key && extra.value != null) {
+ context.fork("default", 0, this, function (context) {
+ context.completions = [
+ [val(opt.value), _("option.currentValue")],
+ [val(opt.defaultValue), _("option.defaultValue")]
+ ].filter(f => (f[0] !== "" && f[0] != null));
+ });
+ context = context.fork("stuff", 0);
+ }
+
context.title = ["Option Value"];
context.quote = Commands.complQuote[Option._quote] || Commands.complQuote[""];
// Not Vim compatible, but is a significant enough improvement
// that it's worth breaking compatibility.
if (isArray(newValues)) {
- context.filters.push(function (i) newValues.indexOf(i.text) == -1);
+ context.filters.push(i => newValues.indexOf(i.text) == -1);
if (op == "+")
- context.filters.push(function (i) curValues.indexOf(i.text) == -1);
+ context.filters.push(i => curValues.indexOf(i.text) == -1);
if (op == "-")
- context.filters.push(function (i) curValues.indexOf(i.text) > -1);
+ context.filters.push(i => curValues.indexOf(i.text) > -1);
memoize(extra, "values", function () {
if (op == "+")
return curValues.concat(newValues);
if (op == "-")
- return curValues.filter(function (v) newValues.indexOf(val) == -1);
+ return curValues.filter(v => newValues.indexOf(val) == -1);
return newValues;
});
}
},
javascript: function initJavascript(dactyl, modules, window) {
const { options, JavaScript } = modules;
- JavaScript.setCompleter(options.get, [function () ([o.name, o.description] for (o in options))]);
+ JavaScript.setCompleter(Options.prototype.get, [() => ([o.name, o.description] for (o in options))]);
},
sanitizer: function initSanitizer(dactyl, modules, window) {
const { sanitizer } = modules;
} catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
-// vim: set fdm=marker sw=4 ts=4 et ft=javascript:
+// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript: