1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-21 10:27:59 +01:00

Start documenting CompletionContext

This commit is contained in:
Kris Maglione
2008-12-19 00:17:18 -05:00
parent 66bd21ec30
commit e56a93a060

View File

@@ -26,6 +26,25 @@ 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. the terms of any one of the MPL, the GPL or the LGPL.
}}} ***** END LICENSE BLOCK *****/ }}} ***** END LICENSE BLOCK *****/
/**
* Creates a new completion context.
*
* @class A class to provide contexts for command completion.
* Manages the filtering and formatting of completions, and keeps
* track of the positions and quoting of replacement text. Allows for
* the creation of sub-contexts with different headers and quoting
* rules.
*
* @param {nsIEditor} editor The editor for which completion is
* intended. May be a {CompletionContext} when forking a context,
* or a {string} when creating a new one.
* @param {string} name The name of this context. Used when the
* context is forked.
* @param {number} offset The offset from the parent context.
* @author Kris Maglione <maglione.k@gmail.com>
* @constructor
*/
function CompletionContext(editor, name, offset) //{{{ function CompletionContext(editor, name, offset) //{{{
{ {
if (!(this instanceof arguments.callee)) if (!(this instanceof arguments.callee))
@@ -44,7 +63,11 @@ function CompletionContext(editor, name, offset) //{{{
else else
self.contexts[name] = this; self.contexts[name] = this;
/**
* @property {CompletionContext} This context's parent. {null} when this is a top-level context.
*/
self.parent = parent; self.parent = parent;
["filters", "keys", "title", "quote"].forEach(function (key) ["filters", "keys", "title", "quote"].forEach(function (key)
self[key] = parent[key] && util.cloneObject(parent[key])); self[key] = parent[key] && util.cloneObject(parent[key]));
["anchored", "compare", "editor", "_filter", "filterFunc", "keys", "_process", "top"].forEach(function (key) ["anchored", "compare", "editor", "_filter", "filterFunc", "keys", "_process", "top"].forEach(function (key)
@@ -55,10 +78,20 @@ function CompletionContext(editor, name, offset) //{{{
self.offset = parent.offset; self.offset = parent.offset;
self.advance(offset); self.advance(offset);
/**
* @property {boolean} Specifies that this context is not finished
* generating results.
* @default false
*/
self.incomplete = false; self.incomplete = false;
self.message = null; self.message = null;
/**
* @property {boolean} Specifies that this context is waiting for the
* user to press <Tab>. Useful when fetching completions could be
* dangerous or slow, and the user has enabled autocomplete.
*/
self.waitingForTab = false; self.waitingForTab = false;
//delete self._filter; // FIXME?
delete self._generate; delete self._generate;
delete self._ignoreCase; delete self._ignoreCase;
if (self != this) if (self != this)
@@ -76,6 +109,11 @@ function CompletionContext(editor, name, offset) //{{{
this.editor = editor; this.editor = editor;
this.compare = function (a, b) String.localeCompare(a.text, b.text); this.compare = function (a, b) String.localeCompare(a.text, b.text);
/**
* @property {function} The function used to filter the results.
* @default Selects all results which match every predicate in the
* {@link #filters} array.
*/
this.filterFunc = function (items) this.filterFunc = function (items)
{ {
let self = this; let self = this;
@@ -83,6 +121,10 @@ function CompletionContext(editor, name, offset) //{{{
reduce(function (res, filter) res.filter(function (item) filter.call(self, item)), reduce(function (res, filter) res.filter(function (item) filter.call(self, item)),
items); items);
} }
/**
* @property {Array} An array of predicates on which to filter the
* results.
*/
this.filters = [function (item) { this.filters = [function (item) {
let text = Array.concat(this.getKey(item, "text")); let text = Array.concat(this.getKey(item, "text"));
for (let [i, str] in Iterator(text)) for (let [i, str] in Iterator(text))
@@ -95,22 +137,73 @@ function CompletionContext(editor, name, offset) //{{{
} }
return false; return false;
}]; }];
/**
* @property {boolean} Specifies whether this context results must
* match the filter at the begining of the string.
* @default true
*/
this.anchored = true; this.anchored = true;
/**
* @property {Object} A map of all contexts, keyed on their names.
* Names are assigned when a context is forked, with its specified
* name appended, after a '/', to its parent's name.
*/
this.contexts = { name: this }; this.contexts = { name: this };
/**
* @property {Object} A mapping of keys, for {@link #getKey}. Given
* { key: value }, getKey(item, key) will return values as such:
* if value is a string, it will return item.item[value]. If it's a
* function, it will return value(item.item).
*/
this.keys = { text: 0, description: 1, icon: "icon" }; this.keys = { text: 0, description: 1, icon: "icon" };
/**
* @property {number} This context's offset from the begining of
* {@link #editor}'s value.
*/
this.offset = offset || 0; this.offset = offset || 0;
/**
* @property {function} A function which is called when any subcontext
* changes its completion list. Only called when
* {@link #updateAsync} is true.
*/
this.onUpdate = function () true; this.onUpdate = function () true;
/**
* @property {CompletionContext} The top-level completion context.
*/
this.top = this; this.top = this;
this.__defineGetter__("incomplete", function () this.contextList.some(function (c) c.parent && c.incomplete)); this.__defineGetter__("incomplete", function () this.contextList.some(function (c) c.parent && c.incomplete));
this.__defineGetter__("waitingForTab", function () this.contextList.some(function (c) c.parent && c.waitingForTab)); this.__defineGetter__("waitingForTab", function () this.contextList.some(function (c) c.parent && c.waitingForTab));
this.reset(); this.reset();
} }
/**
* @property {Object} A general-purpose store for functions which need to
* cache data between calls.
*/
this.cache = {}; this.cache = {};
/**
* @private
* @property {Object} A cache for return values of {@link #generate}.
*/
this.itemCache = {}; this.itemCache = {};
/**
* @property {string} A key detailing when the cached value of
* {@link #generate} may be used. Every call to
* {@link #generate} stores its result in {@link #itemCache}.
* When itemCache[key] exists, its value is returned, and
* {@link #generate} is not called again.
*/
this.key = ""; this.key = "";
/**
* @property {string} A message to be shown before any results.
*/
this.message = null; this.message = null;
this.name = name || ""; this.name = name || "";
/** @private */
this._completions = []; // FIXME this._completions = []; // FIXME
/**
* 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 (item, key) (typeof self.keys[key] == "function") ? self.keys[key].call(this, item.item) :
key in self.keys ? item.item[self.keys[key]] key in self.keys ? item.item[self.keys[key]]
: item.item[key]; : item.item[key];
@@ -118,6 +211,14 @@ function CompletionContext(editor, name, offset) //{{{
CompletionContext.prototype = { CompletionContext.prototype = {
// Temporary // Temporary
/**
* @property {Object}
*
* An object describing the results from all sub-contexts. Results are
* adjusted so that all have the same starting offset.
*
* @deprecated
*/
get allItems() get allItems()
{ {
try try
@@ -372,6 +473,19 @@ CompletionContext.prototype = {
return this._substrings = substrings; return this._substrings = substrings;
}, },
/**
* Advances the context <b>count</b> characters. {@link #filter} is
* advanced to match. If {@link #quote} is non-null, its prefix and suffix
* are set to the null-string.
*
* This function is still imperfect for quoted strings. When
* {@link #quote} is non-null, it adjusts the count based on the quoted
* size of the <b>count</b>-character substring of the filter, which is
* accurate so long as unquoting and quoting a string will always map to
* the original quoted string, which is often not the case.
*
* @param {number} count The number of characters to advance the context.
*/
advance: function advance(count) advance: function advance(count)
{ {
delete this._ignoreCase; delete this._ignoreCase;
@@ -386,6 +500,12 @@ CompletionContext.prototype = {
this._filter = this._filter.substr(count); this._filter = this._filter.substr(count);
}, },
/**
* Gets a key from {@link #cache}, setting it to <b>defVal</b> if it
* doesn't already exists.
* @param {string} key
* @param defVal
*/
getCache: function (key, defVal) getCache: function (key, defVal)
{ {
if (!(key in this.cache)) if (!(key in this.cache))
@@ -511,6 +631,13 @@ CompletionContext.prototype = {
} }
}, },
/**
* Wait for all subcontexts to complete.
*
* @param {boolean} interruptable When true, the call may be interrupted
* via <C-c>. In this case, "Interrupted" may be thrown.
* @param {number} timeout The maximum time, in milliseconds, to wait.
*/
wait: function wait(interruptable, timeout) wait: function wait(interruptable, timeout)
{ {
let end = Date.now() + timeout; let end = Date.now() + timeout;