1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-20 06:07:59 +01:00

Completion internals work.

This commit is contained in:
Kris Maglione
2011-10-03 02:53:42 -04:00
parent 22e798f59f
commit cdd184fe64

View File

@@ -1093,6 +1093,8 @@ var CommandLine = Module("commandline", {
lastSubstring: "", lastSubstring: "",
get activeContexts() this.context.activeContexts,
get completion() { get completion() {
let str = commandline.command; let str = commandline.command;
return str.substring(this.prefix.length, str.length - this.suffix.length); return str.substring(this.prefix.length, str.length - this.suffix.length);
@@ -1144,15 +1146,40 @@ var CommandLine = Module("commandline", {
haveType: function haveType(type) haveType: function haveType(type)
this.wildmode.checkHas(this.wildtype, type == "first" ? "" : type), this.wildmode.checkHas(this.wildtype, type == "first" ? "" : type),
getItem: function getItem(tuple) {
tuple = tuple || this.selected;
return tuple[0].items[tuple[1]];
},
nextItem: function nextItem(tuple, offset, noWrap) {
if (!this.activeContexts.length)
return null;
if (tuple === undefined)
tuple = this.selected;
if (!tuple) {
// kludge.
noWrap = false;
if (offset < 0)
tuple = [this.activeContexts[0], 0];
else {
let ctxt = this.activeContexts.slice(-1)[0];
tuple = [ctxt, ctxt.items.length - 1];
}
}
return this.itemList.getRelativeItem(offset || 1, tuple, noWrap);
},
preview: function preview() { preview: function preview() {
this.previewClear(); this.previewClear();
if (this.wildIndex < 0 || this.suffix || !this.items.length) if (this.wildIndex < 0 || this.suffix || !this.activeContexts.length)
return; return;
let substring = ""; let substring = "";
switch (this.wildtype.replace(/.*:/, "")) { switch (this.wildtype.replace(/.*:/, "")) {
case "": case "":
substring = this.items[0].result; substring = this.getItem(this.nextItem(null)).result;
break; break;
case "longest": case "longest":
if (this.items.length > 1) { if (this.items.length > 1) {
@@ -1161,9 +1188,9 @@ var CommandLine = Module("commandline", {
} }
// Fallthrough // Fallthrough
case "full": case "full":
let item = this.items[this.selected != null ? this.selected + 1 : 0]; let item = this.nextItem();
if (item) if (item)
substring = item.result; substring = this.getItem(item).result;
break; break;
} }
@@ -1237,10 +1264,10 @@ var CommandLine = Module("commandline", {
if (group && group.context == context && this.completion) { if (group && group.context == context && this.completion) {
this.selected = null; this.selected = null;
if (group.selectedIdx != null) if (group.selectedIdx != null)
this.selected = group.getOffset(group.selectedIdx); this.selected = [group.context, group.selectedIdx];
this.completion = this.selected in this.items ? this.items[this.selected].result this.completion = this.selected ? this.getItem().result
: this.value; : this.value;
} }
this.preview(); this.preview();
@@ -1248,102 +1275,78 @@ var CommandLine = Module("commandline", {
_select: function _select(dir, idx) { _select: function _select(dir, idx) {
switch (dir) { switch (dir) {
case this.CTXT_UP:
case this.CTXT_DOWN:
let groups = this.itemList.activeGroups;
let i = Math.max(0, groups.indexOf(this.itemList.selectedGroup));
i += dir == this.CTXT_DOWN ? 1 : -1;
i %= groups.length;
if (i < 0)
i += groups.length;
var position = 0;
var group = groups[i];
break;
case this.PAGE_UP:
case this.PAGE_DOWN:
[group, idx] = this.itemList.getRelativePage(dir == this.PAGE_DOWN ? 1 : -1);
group = this.itemList.getGroup(group);
break;
default: default:
return false; return false;
} }
this.wildIndex = this.wildtypes.length - 1; this.selected = [group.context, idx];
this.selected = group.offsets.start + idx; this.completion = this.getItem().result;
this.completion = this.items[this.selected].result;
this.itemList.select(group.context, idx, position); this.itemList.select(group.context, idx, position);
return true; return true;
}, },
select: function select(idx, count) { select: function select(idx, count, fromTab) {
count = count || 1;
switch (idx) { switch (idx) {
case this.UP: case this.UP:
if (this.selected == null)
idx = -1 - count;
else
idx = this.selected - count;
break;
case this.DOWN: case this.DOWN:
if (this.selected == null) idx = this.nextItem(this.selected, idx == this.UP ? -count : count,
idx = count - 1; true);
else
idx = this.selected + count;
break; break;
case this.CTXT_UP:
case this.CTXT_DOWN:
let groups = this.itemList.activeGroups;
let i = Math.max(0, groups.indexOf(this.itemList.selectedGroup));
i += idx == this.CTXT_DOWN ? 1 : -1;
i %= groups.length;
if (i < 0)
i += groups.length;
var position = 0;
idx = [groups[i].context, 0];
break;
case this.PAGE_UP:
case this.PAGE_DOWN:
idx = this.itemList.getRelativePage(idx == this.PAGE_DOWN ? 1 : -1);
break;
case this.RESET: case this.RESET:
idx = null; idx = null;
break; break;
default: default:
if (this._select(idx, 0))
return;
idx = Math.constrain(idx, 0, this.items.length - 1);
break; break;
} }
if (idx == -1 || this.items.length && idx >= this.items.length || idx == null) { if (!fromTab)
this.wildIndex = this.wildtypes.length - 1;
if (idx == null || !this.activeContexts.length) {
// Wrapped. Start again. // Wrapped. Start again.
this.selected = null; this.selected = null;
this.completion = this.value; this.completion = this.value;
} }
else { else {
// Wait for contexts to complete if necessary.
// FIXME: Need to make idx relative to individual contexts.
let list = this.context.contextList;
if (idx == -2)
list = list.slice().reverse();
let n = 0;
try {
this.waiting = true;
for (let [, context] in Iterator(list)) {
let done = function done() !(idx >= n + context.items.length || idx == -2 && !context.items.length);
util.waitFor(function () !context.incomplete || done());
if (done())
break;
n += context.items.length;
}
}
finally {
this.waiting = false;
}
// See previous FIXME. This will break if new items in
// a previous context come in.
if (idx < 0)
idx = this.items.length - 1;
if (this.items.length == 0)
return;
this.selected = idx; this.selected = idx;
this.completion = this.items[idx].result; this.completion = this.getItem().result;
} }
this.itemList.selectItem(idx); this.itemList.select(idx, null, position);
this.preview();
if (this.selected == null)
statusline.progress = "";
else
statusline.progress = _("completion.matchIndex",
this.itemList.getOffset(idx),
this.itemList.itemCount);
}, },
tabs: [], tabs: [],
@@ -1361,39 +1364,38 @@ var CommandLine = Module("commandline", {
this.complete(true, true); this.complete(true, true);
this.tabs.push([count, wildmode || options["wildmode"]]); this.tabs.push([count, wildmode || options["wildmode"]]);
if (this.waiting) if (this.waiting && false)
return; return;
while (this.tabs.length) { while (this.tabs.length) {
[count, this.wildtypes] = this.tabs.shift(); [count, this.wildtypes] = this.tabs.shift();
let steps = Math.constrain(this.wildtypes.length - this.wildIndex, 1, count);
count = Math.max(1, count - steps);
this.wildIndex = Math.min(this.wildIndex, this.wildtypes.length - 1); while (steps--) {
switch (this.wildtype.replace(/.*:/, "")) { this.wildIndex = Math.min(this.wildIndex, this.wildtypes.length - 1);
case "": switch (this.wildtype.replace(/.*:/, "")) {
this.select(0); case "":
break; this.select(this.nextItem(null));
case "longest": break;
if (this.items.length > 1) { case "longest":
if (this.substring && this.substring.length > this.completion.length) if (this.items.length > 1) {
this.completion = this.substring; if (this.substring && this.substring.length > this.completion.length)
this.completion = this.substring;
break;
}
// Fallthrough
case "full":
let c = steps ? 1 : count;
this.select(c < 0 ? this.UP : this.DOWN, Math.abs(c), true);
break; break;
} }
// Fallthrough
case "full": if (this.haveType("list"))
this.select(count < 0 ? this.UP : this.DOWN, Math.abs(count)); this.itemList.visible = true;
break;
this.wildIndex++;
} }
if (this.haveType("list"))
this.itemList.visible = true;
this.wildIndex++;
this.preview();
if (this.selected == null)
statusline.progress = "";
else
statusline.progress = _("completion.matchIndex", this.selected + 1, this.items.length);
} }
if (this.items.length == 0) if (this.items.length == 0)
@@ -1732,30 +1734,43 @@ var ItemList = Class("ItemList", {
|| c.hasItems && c.items.length) || c.hasItems && c.items.length)
.map(this.getGroup, this), .map(this.getGroup, this),
getRelativePage: function getRelativePage(offset) { getRelativeItem: function getRelativeItem(offset, tuple, noWrap) {
let groups = this.activeGroups; let groups = this.activeGroups;
let group = this.selectedGroup || groups[0];
let start = group.offsets.start + (group.selectedIdx || 0); let group = this.selectedGroup || groups[0];
start = (start + (this.maxItems * offset)) % this.itemCount;; let start = group.selectedIdx || 0;
if (tuple)
[group, start] = tuple;
group = this.getGroup(group);
start = (group.offsets.start + start + offset);
if (!noWrap)
start %= this.itemCount;
if (start < 0) if (start < 0)
start += this.itemCount; start += this.itemCount;
if (start < 0 || start >= this.itemCount)
return null;
group = array.nth(groups, function (g) let (i = start - g.offsets.start) i >= 0 && i < g.itemCount, 0) group = array.nth(groups, function (g) let (i = start - g.offsets.start) i >= 0 && i < g.itemCount, 0)
return [group.context, start - group.offsets.start]; return [group.context, start - group.offsets.start];
}, },
getRelativePage: function getRelativePage(offset, tuple, noWrap) {
return this.getRelativeItem(offset * this.maxItems, tuple);
},
open: function open(context) { open: function open(context) {
this.context = context; this.context = context;
this.nodes = {}; this.nodes = {};
this.maxHeight = 0; this.container.height = 0;
this.minHeight = 0;
this.maxItems = options["maxitems"]; this.maxItems = options["maxitems"];
DOM(this.rootXML, this.doc, this.nodes) DOM(this.rootXML, this.doc, this.nodes)
.appendTo(DOM(this.body).empty()); .appendTo(DOM(this.body).empty());
this.update(); this.update();
this.visible = true;
}, },
updateOffsets: function updateOffsets() { updateOffsets: function updateOffsets() {
@@ -1853,8 +1868,10 @@ var ItemList = Class("ItemList", {
}, },
select: function select(group, index, position) { select: function select(group, index, position) {
if (group && !(group instanceof ItemList.Group)) if (isArray(group))
group = this.getGroup(group); [group, index] = group;
group = this.getGroup(group);
if (this.selectedGroup && (!group || group != this.selectedGroup)) if (this.selectedGroup && (!group || group != this.selectedGroup))
this.selectedGroup.selectedIdx = null; this.selectedGroup.selectedIdx = null;
@@ -1915,8 +1932,12 @@ var ItemList = Class("ItemList", {
this.select(group && group.context, idx); this.select(group && group.context, idx);
}, },
getGroup: function getGroup(context) context && getGroup: function getGroup(context)
context.getCache("itemlist-group", bind("Group", ItemList, this, context)) context instanceof ItemList.Group ? context
: context && context.getCache("itemlist-group",
bind("Group", ItemList, this, context)),
getOffset: function getOffset(tuple) this.getGroup(tuple[0]).getOffset(tuple[1])
}, { }, {
RESIZE_BRIEF: 1 << 0, RESIZE_BRIEF: 1 << 0,