// 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-2012 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.
"use strict";
-try {
-
-Components.utils.import("resource://dactyl/bootstrap.jsm");
defineModule("completion", {
- exports: ["CompletionContext", "Completion", "completion"],
- use: ["config", "template", "util"]
+ exports: ["CompletionContext", "Completion", "completion"]
}, this);
+lazyRequire("dom", ["DOM"]);
+lazyRequire("messages", ["_", "messages"]);
+lazyRequire("template", ["template"]);
+
/**
* Creates a new completion context.
*
* @constructor
*/
var CompletionContext = Class("CompletionContext", {
- init: function (editor, name, offset) {
+ init: function cc_init(editor, name, offset) {
if (!name)
name = "";
*/
self.parent = parent;
- ["filters", "keys", "process", "title", "quote"].forEach(function (key)
+ ["filters", "keys", "process", "title", "quote"].forEach(function fe(key)
self[key] = parent[key] && util.cloneObject(parent[key]));
["anchored", "compare", "editor", "_filter", "filterFunc", "forceAnchored", "top"].forEach(function (key)
self[key] = parent[key]);
- self.__defineGetter__("value", function () this.top.value);
+ self.__defineGetter__("value", function get_value() this.top.value);
self.offset = parent.offset;
self.advance(offset || 0);
delete self.ignoreCase;
if (self != this)
return self;
- ["_caret", "contextList", "maxItems", "onUpdate", "selectionTypes", "tabPressed", "updateAsync", "value"].forEach(function (key) {
+ ["_caret", "contextList", "maxItems", "onUpdate", "selectionTypes", "tabPressed", "updateAsync", "value"].forEach(function fe(key) {
self.__defineGetter__(key, function () this.top[key]);
self.__defineSetter__(key, function (val) this.top[key] = val);
});
this.anchored = true;
this.forceAnchored = null;
- this.compare = function (a, b) String.localeCompare(a.text, b.text);
+ this.compare = function compare(a, b) String.localeCompare(a.text, b.text);
/**
* @property {function} This function is called when we close
* a completion window with Esc or Ctrl-c. Usually this callback
* @default Selects all results which match every predicate in the
* {@link #filters} array.
*/
- this.filterFunc = function (items) {
+ this.filterFunc = function filterFunc(items) {
let self = this;
return this.filters.
- reduce(function (res, filter) res.filter(function (item) filter.call(self, item)),
+ reduce(function r(res, filter) res.filter(function f(item) filter.call(self, item)),
items);
};
/**
* changes its completion list. Only called when
* {@link #updateAsync} is true.
*/
- this.onUpdate = function () true;
+ this.onUpdate = function onUpdate() true;
this.runCount = 0;
* @property {CompletionContext} The top-level completion context.
*/
this.top = this;
- this.__defineGetter__("incomplete", function () this._incomplete || this.contextList.some(function (c) c.parent && c.incomplete));
- this.__defineGetter__("waitingForTab", function () this._waitingForTab || this.contextList.some(function (c) c.parent && c.waitingForTab));
- this.__defineSetter__("incomplete", function (val) { this._incomplete = val; });
- this.__defineSetter__("waitingForTab", function (val) { this._waitingForTab = val; });
+ this.__defineGetter__("incomplete", function get_incomplete() this._incomplete
+ || this.contextList.some(function (c) c.parent && c.incomplete));
+ this.__defineGetter__("waitingForTab", function get_waitingForTab() this._waitingForTab
+ || this.contextList.some(function (c) c.parent && c.waitingForTab));
+ this.__defineSetter__("incomplete", function get_incomplete(val) { this._incomplete = val; });
+ this.__defineSetter__("waitingForTab", function get_waitingForTab(val) { this._waitingForTab = val; });
this.reset();
}
/**
* Returns a key, as detailed in {@link #keys}.
* @function
*/
- this.getKey = function (item, key) (typeof self.keys[key] == "function") ? self.keys[key].call(this, item.item) :
+ this.getKey = function getKey(item, key) (typeof self.keys[key] == "function") ? self.keys[key].call(this, item.item) :
key in self.keys ? item.item[self.keys[key]]
: item.item[key];
return this;
},
+ __title: Class.Memoize(function __title() this._title.map(function (s)
+ typeof s == "string" ? messages.get("completion.title." + s, s)
+ : s)),
+
+ set title(val) {
+ delete this.__title;
+ return this._title = val;
+ },
+ get title() this.__title,
+
+ get activeContexts() this.contextList.filter(function f(c) c.items.length),
+
// Temporary
/**
* @property {Object}
* @deprecated
*/
get allItems() {
+ let self = this;
+
try {
- let self = this;
- let allItems = this.contextList.map(function (context) context.hasItems && context.items);
+ let allItems = this.contextList.map(function m(context) context.hasItems && context.items.length);
if (this.cache.allItems && array.equals(this.cache.allItems, allItems))
return this.cache.allItemsResult;
this.cache.allItems = allItems;
- let minStart = Math.min.apply(Math, [context.offset for ([k, context] in Iterator(this.contexts)) if (context.hasItems && context.items.length)]);
+ let minStart = Math.min.apply(Math, this.activeContexts.map(function m(c) c.offset));
if (minStart == Infinity)
minStart = 0;
- let items = this.contextList.map(function (context) {
- if (!context.hasItems)
- return [];
- let prefix = self.value.substring(minStart, context.offset);
- return context.items.map(function (item) ({
- text: prefix + item.text,
- result: prefix + item.result,
- __proto__: item
- }));
+
+ this.cache.allItemsResult = memoize({
+ start: minStart,
+
+ get longestSubstring() self.longestAllSubstring,
+
+ get items() array.flatten(self.activeContexts.map(function m(context) {
+ let prefix = self.value.substring(minStart, context.offset);
+
+ return context.items.map(function m(item) ({
+ text: prefix + item.text,
+ result: prefix + item.result,
+ __proto__: item
+ }));
+ }))
});
- this.cache.allItemsResult = { start: minStart, items: array.flatten(items) };
- memoize(this.cache.allItemsResult, "longestSubstring", function () self.longestAllSubstring);
+
return this.cache.allItemsResult;
}
catch (e) {
},
// Temporary
get allSubstrings() {
- let contexts = this.contextList.filter(function (c) c.hasItems && c.items.length);
- let minStart = Math.min.apply(Math, contexts.map(function (c) c.offset));
- let lists = contexts.map(function (context) {
+ let contexts = this.activeContexts;
+ let minStart = Math.min.apply(Math, contexts.map(function m(c) c.offset));
+ let lists = contexts.map(function m(context) {
let prefix = context.value.substring(minStart, context.offset);
- return context.substrings.map(function (s) prefix + s);
+ return context.substrings.map(function m(s) prefix + s);
});
/* TODO: Deal with sub-substrings for multiple contexts again.
* Possibly.
*/
let substrings = lists.reduce(
- function (res, list) res.filter(function (str) list.some(function (s) s.substr(0, str.length) == str)),
+ function r(res, list) res.filter(function f(str) list.some(function s_(s) s.substr(0, str.length) == str)),
lists.pop());
if (!substrings) // FIXME: How is this undefined?
return [];
},
// Temporary
get longestAllSubstring() {
- return this.allSubstrings.reduce(function (a, b) a.length > b.length ? a : b, "");
+ return this.allSubstrings.reduce(function r(a, b) a.length > b.length ? a : b, "");
},
get caret() this._caret - this.offset,
set caret(val) this._caret = val + this.offset,
- get compare() this._compare || function () 0,
+ get compare() this._compare || function compare() 0,
set compare(val) this._compare = val,
get completions() this._completions || [],
this._completions = items;
this.itemCache[this.key] = items;
}
+
if (this._completions)
this.hasItems = this._completions.length > 0;
+
if (this.updateAsync && !this.noUpdate)
- this.onUpdate();
+ util.trapErrors("onUpdate", this);
},
get createRow() this._createRow || template.completionRow, // XXX
* The message displayed at the head of the completions for the
* current context.
*/
- get message() this._message || (this.waitingForTab && this.hasItems !== false ? "Waiting for <Tab>" : null),
+ get message() this._message || (this.waitingForTab && this.hasItems !== false ? _("completion.waitingFor", "<Tab>") : null),
set message(val) this._message = val,
/**
* The prototype object for items returned by {@link items}.
*/
get itemPrototype() {
- let res = {};
+ let self = this;
+ let res = { highlight: "" };
+
function result(quote) {
- yield ["result", quote ? function () quote[0] + quote[1](this.text) + quote[2]
- : function () this.text];
+ yield ["context", function p_context() self];
+ yield ["result", quote ? function p_result() quote[0] + util.trapErrors(1, quote, this.text) + quote[2]
+ : function p_result() this.text];
+ yield ["texts", function p_texts() Array.concat(this.text)];
};
+
for (let i in iter(this.keys, result(this.quote))) {
let [k, v] = i;
if (typeof v == "string" && /^[.[]/.test(v))
// reference any variables. Don't bother with eval context.
v = Function("i", "return i" + v);
if (typeof v == "function")
- res.__defineGetter__(k, function () Class.replaceProperty(this, k, v.call(this, this.item)));
+ res.__defineGetter__(k, function p_gf() Class.replaceProperty(this, k, v.call(this, this.item, self)));
else
- res.__defineGetter__(k, function () Class.replaceProperty(this, k, this.item[v]));
- res.__defineSetter__(k, function (val) Class.replaceProperty(this, k, val));
+ res.__defineGetter__(k, function p_gp() Class.replaceProperty(this, k, this.item[v]));
+ res.__defineSetter__(k, function p_s(val) Class.replaceProperty(this, k, val));
}
return res;
},
this._cache.offset = this.offset;
this.lastActivated = this.top.runCount;
}
- if (!this.itemCache[this.key]) {
+ if (!this.itemCache[this.key] && !this.waitingForTab) {
try {
let res = this._generate();
if (res != null)
}
catch (e) {
util.reportError(e);
- this.message = "Error: " + e;
+ this.message = _("error.error", e);
}
}
// XXX
this.noUpdate = false;
},
- ignoreCase: Class.memoize(function () {
+ ignoreCase: Class.Memoize(function M() {
let mode = this.wildcase;
if (mode == "match")
return false;
// Item matchers
if (this.ignoreCase)
this.matchString = this.anchored ?
- function (filter, str) String.toLowerCase(str).indexOf(filter.toLowerCase()) == 0 :
- function (filter, str) String.toLowerCase(str).indexOf(filter.toLowerCase()) >= 0;
+ function matchString(filter, str) String.toLowerCase(str).indexOf(filter.toLowerCase()) == 0 :
+ function matchString(filter, str) String.toLowerCase(str).indexOf(filter.toLowerCase()) >= 0;
else
this.matchString = this.anchored ?
- function (filter, str) String.indexOf(str, filter) == 0 :
- function (filter, str) String.indexOf(str, filter) >= 0;
+ function matchString(filter, str) String.indexOf(str, filter) == 0 :
+ function matchString(filter, str) String.indexOf(str, filter) >= 0;
// Item formatters
this.processor = Array.slice(this.process);
if (!this.anchored)
- this.processor[0] = function (item, text) self.process[0].call(self, item,
- template.highlightFilter(item.text, self.filter));
+ this.processor[0] = function processor_0(item, text) self.process[0].call(self, item,
+ template.highlightFilter(item.text, self.filter, null, item.isURI));
try {
// Item prototypes
if (!this._cache.constructed) {
let proto = this.itemPrototype;
- this._cache.constructed = items.map(function (item) ({ __proto__: proto, item: item }));
+ this._cache.constructed = items.map(function m(item) ({ __proto__: proto, item: item }));
}
// Filters
filtered.sort(this.compare);
if (!this.anchored) {
let filter = this.filter;
- filtered.sort(function (a, b) (b.text.indexOf(filter) == 0) - (a.text.indexOf(filter) == 0));
+ filtered.sort(function s(a, b) (b.text.indexOf(filter) == 0) - (a.text.indexOf(filter) == 0));
}
}
return this.cache.filtered = filtered;
}
catch (e) {
- this.message = "Error: " + e;
+ this.message = _("error.error", e);
util.reportError(e);
return [];
}
}
}
- substrings = items.reduce(function (res, item)
- res.map(function (substring) {
+ substrings = items.reduce(function r(res, item)
+ res.map(function m(substring) {
// A simple binary search to find the longest substring
// of the given string which also matches the current
// item's text.
let len = substring.length;
- let i = 0, n = len;
+ let i = 0, n = len + 1;
+ let result = n && fixCase(item.result);
while (n) {
let m = Math.floor(n / 2);
- let keep = compare(fixCase(item.text), substring.substring(0, i + m));
+ let keep = compare(result, substring.substring(0, i + m));
if (!keep)
len = i + m - 1;
if (!keep || m == 0)
let quote = this.quote;
if (quote)
- substrings = substrings.map(function (str) quote[0] + quote[1](str));
+ substrings = substrings.map(function m(str) quote[0] + quote[1](str));
return this._substrings = substrings;
},
}
this.offset += count;
if (this._filter)
- this._filter = this._filter.substr(advance);
+ this._filter = this._filter.substr(arguments[0] || 0);
},
/**
* Calls the {@link #cancel} method of all currently active
* sub-contexts.
*/
- cancelAll: function () {
+ cancelAll: function cancelAll() {
for (let [, context] in Iterator(this.contextList)) {
if (context.cancel)
context.cancel();
* @param {string} key
* @param defVal
*/
- getCache: function (key, defVal) {
+ getCache: function getCache(key, defVal) {
if (!(key in this.cache))
this.cache[key] = defVal();
return this.cache[key];
let step = start > end ? -1 : 1;
start = Math.max(0, start || 0);
end = Math.min(items.length, end ? end : items.length);
- return iter.map(util.range(start, end, step), function (i) items[i]);
+ return iter.map(util.range(start, end, step), function m(i) items[i]);
+ },
+
+ getRow: function getRow(idx, doc) {
+ let cache = this.cache.rows;
+ if (cache) {
+ if (idx in this.items && !(idx in this.cache.rows))
+ try {
+ cache[idx] = DOM.fromJSON(this.createRow(this.items[idx]),
+ doc || this.doc);
+ }
+ catch (e) {
+ util.reportError(e);
+ util.dump(util.prettifyJSON(this.createRow(this.items[idx]), null, true));
+ cache[idx] = DOM.fromJSON(
+ ["div", { highlight: "CompItem", style: "white-space: nowrap" },
+ ["li", { highlight: "CompResult" }, this.text + "\u00a0"],
+ ["li", { highlight: "CompDesc ErrorMsg" }, e + "\u00a0"]],
+ doc || this.doc);
+ }
+ return cache[idx];
+ }
},
getRows: function getRows(start, end, doc) {
let items = this.items;
let cache = this.cache.rows;
let step = start > end ? -1 : 1;
+
start = Math.max(0, start || 0);
end = Math.min(items.length, end != null ? end : items.length);
+
+ this.doc = doc;
for (let i in util.range(start, end, step))
- yield [i, cache[i] = cache[i] || util.xmlToDom(self.createRow(items[i]), doc)];
+ yield [i, this.getRow(i)];
},
/**
let context = this.fork(name);
function alias(prop) {
- context.__defineGetter__(prop, function () self[prop]);
- context.__defineSetter__(prop, function (val) self[prop] = val);
+ context.__defineGetter__(prop, function get_() self[prop]);
+ context.__defineSetter__(prop, function set_(val) self[prop] = val);
}
alias("_cache");
alias("_completions");
*/
pushProcessor: function pushProcess(index, func) {
let next = this.process[index];
- this.process[index] = function (item, text) func(item, text, next);
+ this.process[index] = function process_(item, text) func(item, text, next);
},
/**
throw Error();
this.offset = 0;
- this.process = [template.icon, function (item, k) k];
+ this.process = [template.icon, function process_1(item, k) k];
this.filters = [CompletionContext.Filter.text];
this.tabPressed = false;
this.title = ["Completions"];
*/
wait: function wait(timeout, interruptable) {
this.allItems;
- return util.waitFor(function () !this.incomplete, this, timeout, interruptable);
+ return util.waitFor(function wf() !this.incomplete, this, timeout, interruptable);
}
}, {
Sort: {
- number: function (a, b) parseInt(a.text) - parseInt(b.text) || String.localeCompare(a.text, b.text),
+ number: function S_number(a, b) parseInt(a.text) - parseInt(b.text)
+ || String.localeCompare(a.text, b.text),
unsorted: null
},
Filter: {
- text: function (item) {
- let text = Array.concat(item.text);
+ text: function F_text(item) {
+ let text = item.texts;
for (let [i, str] in Iterator(text)) {
if (this.match(String(str))) {
item.text = String(text[i]);
}
return false;
},
- textDescription: function (item) {
+ textDescription: function F_textDescription(item) {
return CompletionContext.Filter.text.call(this, item) || this.match(item.description);
}
}
* @instance completion
*/
var Completion = Module("completion", {
- init: function () {
+ init: function init() {
},
get setFunctionCompleter() JavaScript.setCompleter, // Backward compatibility
- Local: function (dactyl, modules, window) ({
+ Local: function Local(dactyl, modules, window) ({
urlCompleters: {},
+ get modules() modules,
get options() modules.options,
// FIXME
let res = context.fork.apply(context, ["run", 0, this, name].concat(Array.slice(arguments, 3)));
if (res) {
if (Components.stack.caller.name === "runCompleter") // FIXME
- return { items: res.map(function (i) ({ item: i })) };
+ return { items: res.map(function m(i) ({ item: i })) };
context.contexts["/run"].completions = res;
}
context.wait(null, true);
runCompleter: function runCompleter(name, filter, maxItems) {
return this._runCompleter.apply(this, Array.slice(arguments))
- .items.map(function (i) i.item);
+ .items.map(function m(i) i.item);
},
listCompleter: function listCompleter(name, filter, maxItems) {
context = context.contexts["/list"];
context.wait(null, true);
- let contexts = context.contextList.filter(function (c) c.hasItems && c.items.length);
+ let contexts = context.activeContexts;
if (!contexts.length)
- contexts = context.contextList.filter(function (c) c.hasItems).slice(0, 1);
+ contexts = context.contextList.filter(function f(c) c.hasItems).slice(0, 1);
if (!contexts.length)
contexts = context.contextList.slice(-1);
modules.commandline.commandOutput(
- <div highlight="Completions">
- { template.map(contexts, function (context)
- template.completionRow(context.title, "CompTitle") +
- template.map(context.items, function (item) context.createRow(item), null, 100)) }
- </div>);
+ ["div", { highlight: "Completions" },
+ template.map(contexts, function m(context)
+ [template.completionRow(context.title, "CompTitle"),
+ template.map(context.items, function m(item) context.createRow(item), null, 100)])]);
},
}),
// depending on the 'complete' option
// if the 'complete' argument is passed like "h", it temporarily overrides the complete option
url: function url(context, complete) {
+ if (/^jar:[^!]*$/.test(context.filter)) {
+ context.advance(4);
+
+ context.quote = context.quote || ["", util.identity, ""];
+ let quote = context.quote[1];
+ context.quote[1] = function quote_1(str) quote(str.replace(/!/g, escape));
+ }
if (this.options["urlseparator"])
var skip = util.regexp("^.*" + this.options["urlseparator"] + "\\s*")
context.advance(skip[0].length);
if (/^about:/.test(context.filter))
- context.fork("about", 6, this, function (context) {
- context.generate = function () {
- const PREFIX = "@mozilla.org/network/protocol/about;1?what=";
- return [[k.substr(PREFIX.length), ""] for (k in Cc) if (k.indexOf(PREFIX) == 0)];
+ context.fork("about", 6, this, function fork_(context) {
+ context.title = ["about:"];
+ context.generate = function generate_() {
+ return [[k.substr(services.ABOUT.length), ""]
+ for (k in Cc)
+ if (k.indexOf(services.ABOUT) == 0)];
};
});
complete = this.options["complete"];
// Will, and should, throw an error if !(c in opts)
- Array.forEach(complete, function (c) {
- let completer = this.urlCompleters[c];
+ Array.forEach(complete, function fe(c) {
+ let completer = this.urlCompleters[c] || { args: [], completer: this.autocomplete(c.replace(/^native:/, "")) };
context.forkapply(c, 0, this, completer.completer, completer.args);
}, this);
},
this.urlCompleters[opt] = completer;
},
- urls: function (context, tags) {
+ autocomplete: curry(function autocomplete(provider, context) {
+ let running = context.getCache("autocomplete-search-running", Object);
+
+ let name = "autocomplete:" + provider;
+ if (!services.has(name))
+ services.add(name, services.AUTOCOMPLETE + provider, "nsIAutoCompleteSearch");
+ let service = services[name];
+
+ util.assert(service, _("autocomplete.noSuchProvider", provider), false);
+
+ if (running[provider]) {
+ this.completions = this.completions;
+ this.cancel();
+ }
+
+ context.anchored = false;
+ context.compare = CompletionContext.Sort.unsorted;
+ context.filterFunc = null;
+
+ let words = context.filter.toLowerCase().split(/\s+/g);
+ context.hasItems = true;
+ context.completions = context.completions.filter(function f({ url, title })
+ words.every(function e(w) (url + " " + title).toLowerCase().indexOf(w) >= 0))
+
+ context.format = this.modules.bookmarks.format;
+ context.keys.extra = function k_extra(item) {
+ try {
+ return bookmarkcache.get(item.url).extra;
+ }
+ catch (e) {}
+ return null;
+ };
+ context.title = [_("autocomplete.title", provider)];
+
+ context.cancel = function cancel_() {
+ this.incomplete = false;
+ if (running[provider])
+ service.stopSearch();
+ running[provider] = false;
+ };
+
+ if (!context.waitingForTab) {
+ context.incomplete = true;
+
+ service.startSearch(context.filter, "", context.result, {
+ onSearchResult: util.wrapCallback(function onSearchResult(search, result) {
+ if (result.searchResult <= result.RESULT_SUCCESS)
+ running[provider] = null;
+
+ context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
+ context.completions = [
+ { url: result.getValueAt(i), title: result.getCommentAt(i), icon: result.getImageAt(i) }
+ for (i in util.range(0, result.matchCount))
+ ];
+ }),
+ get onUpdateSearchResult() this.onSearchResult
+ });
+ running[provider] = true;
+ }
+ }),
+
+ urls: function urls(context, tags) {
let compare = String.localeCompare;
let contains = String.indexOf;
if (context.ignoreCase) {
compare = util.compareIgnoreCase;
- contains = function (a, b) a && a.toLowerCase().indexOf(b.toLowerCase()) > -1;
+ contains = function contains_(a, b) a && a.toLowerCase().indexOf(b.toLowerCase()) > -1;
}
if (tags)
- context.filters.push(function (item) tags.
- every(function (tag) (item.tags || []).
- some(function (t) !compare(tag, t))));
+ context.filters.push(function filter_(item) tags.
+ every(function e(tag) (item.tags || []).
+ some(function s(t) !compare(tag, t))));
context.anchored = false;
if (!context.title)
context.title = ["URL", "Title"];
- context.fork("additional", 0, this, function (context) {
- context.title[0] += " (additional)";
+ context.fork("additional", 0, this, function fork_(context) {
+ context.title[0] += " " + _("completion.additional");
context.filter = context.parent.filter; // FIXME
context.completions = context.parent.completions;
+
// For items whose URL doesn't exactly match the filter,
// accept them if all tokens match either the URL or the title.
// Filter out all directly matching strings.
let match = context.filters[0];
- context.filters[0] = function (item) !match.call(this, item);
+ context.filters[0] = function filters_0(item) !match.call(this, item);
+
// and all that don't match the tokens.
let tokens = context.filter.split(/\s+/);
- context.filters.push(function (item) tokens.every(
- function (tok) contains(item.url, tok) ||
+ context.filters.push(function filter_(item) tokens.every(
+ function e(tok) contains(item.url, tok) ||
contains(item.title, tok)));
let re = RegExp(tokens.filter(util.identity).map(util.regexp.escape).join("|"), "g");
function highlight(item, text, i) process[i].call(this, item, template.highlightRegexp(text, re));
let process = context.process;
context.process = [
- function (item, text) highlight.call(this, item, item.text, 0),
- function (item, text) highlight.call(this, item, text, 1)
+ function process_0(item, text) highlight.call(this, item, item.text, 0),
+ function process_1(item, text) highlight.call(this, item, text, 1)
];
});
}
get options() this.modules.options
});
},
- commands: function (dactyl, modules, window) {
+ commands: function initCommands(dactyl, modules, window) {
const { commands, completion } = modules;
commands.add(["contexts"],
"List the completion contexts used during completion of an Ex command",
function (args) {
modules.commandline.commandOutput(
- <div highlight="Completions">
- { template.completionRow(["Context", "Title"], "CompTitle") }
- { template.map(completion.contextList || [], function (item) template.completionRow(item, "CompItem")) }
- </div>);
+ ["div", { highlight: "Completions" },
+ template.completionRow(["Context", "Title"], "CompTitle"),
+ template.map(completion.contextList || [],
+ function m(item) template.completionRow(item, "CompItem"))]);
},
{
argCount: "*",
literal: 0
});
},
- options: function (dactyl, modules, window) {
+ options: function initOptions(dactyl, modules, window) {
const { completion, options } = modules;
let wildmode = {
values: {
return first == val || second == val;
},
has: function () {
- test = function (val) this.value.some(function (value) this.checkHas(value, val), this);
+ let test = function test(val) this.value.some(function s(value) this.checkHas(value, val), this);
return Array.some(arguments, test, this);
}
};
options.add(["altwildmode", "awim"],
- "Define the behavior of the <A-Tab> key in command-line completion",
+ "Define the behavior of the c_<A-Tab> key in command-line completion",
"stringlist", "list:full",
wildmode);
options.add(["complete", "cpt"],
"Items which are completed at the :open prompts",
- "charlist", config.defaults.complete == null ? "slf" : config.defaults.complete,
- { get values() values(completion.urlCompleters).toArray() });
+ "stringlist", "slf",
+ {
+ valueMap: {
+ S: "suggestion",
+ b: "bookmark",
+ f: "file",
+ h: "history",
+ l: "location",
+ s: "search"
+ },
+
+ get values() values(completion.urlCompleters).toArray()
+ .concat([let (name = k.substr(services.AUTOCOMPLETE.length))
+ ["native:" + name, _("autocomplete.description", name)]
+ for (k in Cc)
+ if (k.indexOf(services.AUTOCOMPLETE) == 0)]),
+
+ setter: function setter(values) {
+ if (values.length == 1 && !Set.has(values[0], this.values)
+ && Array.every(values[0], Set.has(this.valueMap)))
+ return Array.map(values[0], function m(v) this[v], this.valueMap);
+ return values;
+ },
+
+ validator: function validator(values) validator.supercall(this, this.setter(values))
+ });
options.add(["wildanchor", "wia"],
"Define which completion groups only match at the beginning of their text",
});
options.add(["wildmode", "wim"],
- "Define the behavior of the <Tab> key in command-line completion",
+ "Define the behavior of the c_<Tab> key in command-line completion",
"stringlist", "list:full",
wildmode);
endModule();
-} catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
+// 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: