mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-20 18:37:58 +01:00
New prototype ItemList implementation. Faster completion scrolling.
This commit is contained in:
@@ -607,7 +607,7 @@ var CommandLine = Module("commandline", {
|
|||||||
let elem = document.getElementById("dactyl-completions-" + node.id);
|
let elem = document.getElementById("dactyl-completions-" + node.id);
|
||||||
util.waitFor(bind(this.widgets._ready, null, elem));
|
util.waitFor(bind(this.widgets._ready, null, elem));
|
||||||
|
|
||||||
node.completionList = ItemList(elem.id);
|
node.completionList = ItemList(elem);
|
||||||
}
|
}
|
||||||
return node.completionList;
|
return node.completionList;
|
||||||
},
|
},
|
||||||
@@ -1038,7 +1038,7 @@ var CommandLine = Module("commandline", {
|
|||||||
this.wildmode = options.get("wildmode");
|
this.wildmode = options.get("wildmode");
|
||||||
this.wildtypes = this.wildmode.value;
|
this.wildtypes = this.wildmode.value;
|
||||||
this.itemList = commandline.completionList;
|
this.itemList = commandline.completionList;
|
||||||
this.itemList.setItems(this.context);
|
this.itemList.open(this.context);
|
||||||
|
|
||||||
dactyl.registerObserver("events.doneFeeding", this.closure.onDoneFeeding, true);
|
dactyl.registerObserver("events.doneFeeding", this.closure.onDoneFeeding, true);
|
||||||
|
|
||||||
@@ -1051,10 +1051,14 @@ var CommandLine = Module("commandline", {
|
|||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
this.tabTimer = Timer(0, 0, function tabTell(event) {
|
this.tabTimer = Timer(0, 0, function tabTell(event) {
|
||||||
this.tab(event.shiftKey, event.altKey && options["altwildmode"]);
|
let tabCount = this.tabCount;
|
||||||
|
this.tabCount = 0;
|
||||||
|
this.tab(tabCount, event.altKey && options["altwildmode"]);
|
||||||
}, this);
|
}, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
tabCount: 0,
|
||||||
|
|
||||||
cleanup: function () {
|
cleanup: function () {
|
||||||
dactyl.unregisterObserver("events.doneFeeding", this.closure.onDoneFeeding);
|
dactyl.unregisterObserver("events.doneFeeding", this.closure.onDoneFeeding);
|
||||||
this.previewClear();
|
this.previewClear();
|
||||||
@@ -1071,8 +1075,15 @@ var CommandLine = Module("commandline", {
|
|||||||
this.ignoredCount = 0;
|
this.ignoredCount = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onTab: function onTab(event) {
|
||||||
|
this.tabCount += event.shiftKey ? -1 : 1;
|
||||||
|
this.tabTimer.tell(event);
|
||||||
|
},
|
||||||
|
|
||||||
UP: {},
|
UP: {},
|
||||||
DOWN: {},
|
DOWN: {},
|
||||||
|
CTXT_UP: {},
|
||||||
|
CTXT_DOWN: {},
|
||||||
PAGE_UP: {},
|
PAGE_UP: {},
|
||||||
PAGE_DOWN: {},
|
PAGE_DOWN: {},
|
||||||
RESET: null,
|
RESET: null,
|
||||||
@@ -1162,14 +1173,16 @@ var CommandLine = Module("commandline", {
|
|||||||
let value = this.completion;
|
let value = this.completion;
|
||||||
if (util.compareIgnoreCase(value, substring.substr(0, value.length)))
|
if (util.compareIgnoreCase(value, substring.substr(0, value.length)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
substring = substring.substr(value.length);
|
substring = substring.substr(value.length);
|
||||||
this.removeSubstring = substring;
|
this.removeSubstring = substring;
|
||||||
|
|
||||||
let node = util.xmlToDom(<span highlight="Preview">{substring}</span>,
|
let node = DOM.fromXML(<span highlight="Preview">{substring}</span>,
|
||||||
document);
|
document);
|
||||||
let start = this.caret;
|
|
||||||
|
this.withSavedValues(["caret"], function () {
|
||||||
this.editor.insertNode(node, this.editor.rootElement, 1);
|
this.editor.insertNode(node, this.editor.rootElement, 1);
|
||||||
this.caret = start;
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
previewClear: function previewClear() {
|
previewClear: function previewClear() {
|
||||||
@@ -1199,7 +1212,7 @@ var CommandLine = Module("commandline", {
|
|||||||
this.suffix = this.context.value.substring(this.caret);
|
this.suffix = this.context.value.substring(this.caret);
|
||||||
|
|
||||||
if (show) {
|
if (show) {
|
||||||
this.itemList.reset();
|
this.itemList.update();
|
||||||
if (this.haveType("list"))
|
if (this.haveType("list"))
|
||||||
this.itemList.visible = true;
|
this.itemList.visible = true;
|
||||||
this.selected = null;
|
this.selected = null;
|
||||||
@@ -1215,25 +1228,25 @@ var CommandLine = Module("commandline", {
|
|||||||
this.value = value.substring(this.start, this.caret);
|
this.value = value.substring(this.start, this.caret);
|
||||||
this.suffix = value.substring(this.caret);
|
this.suffix = value.substring(this.caret);
|
||||||
|
|
||||||
this.itemList.reset();
|
this.itemList.update();
|
||||||
this.itemList.selectItem(this.selected);
|
this.itemList.selectItem(this.selected);
|
||||||
|
|
||||||
this.preview();
|
this.preview();
|
||||||
},
|
},
|
||||||
|
|
||||||
select: function select(idx) {
|
select: function select(idx, count) {
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
case this.UP:
|
case this.UP:
|
||||||
if (this.selected == null)
|
if (this.selected == null)
|
||||||
idx = -2;
|
idx = -1 - count;
|
||||||
else
|
else
|
||||||
idx = this.selected - 1;
|
idx = this.selected - count;
|
||||||
break;
|
break;
|
||||||
case this.DOWN:
|
case this.DOWN:
|
||||||
if (this.selected == null)
|
if (this.selected == null)
|
||||||
idx = 0;
|
idx = count - 1;
|
||||||
else
|
else
|
||||||
idx = this.selected + 1;
|
idx = this.selected + count;
|
||||||
break;
|
break;
|
||||||
case this.RESET:
|
case this.RESET:
|
||||||
idx = null;
|
idx = null;
|
||||||
@@ -1287,7 +1300,7 @@ var CommandLine = Module("commandline", {
|
|||||||
|
|
||||||
tabs: [],
|
tabs: [],
|
||||||
|
|
||||||
tab: function tab(reverse, wildmode) {
|
tab: function tab(count, wildmode) {
|
||||||
this.autocompleteTimer.flush();
|
this.autocompleteTimer.flush();
|
||||||
this.ignoredCount = 0;
|
this.ignoredCount = 0;
|
||||||
|
|
||||||
@@ -1299,12 +1312,12 @@ var CommandLine = Module("commandline", {
|
|||||||
if (this.context.waitingForTab || this.wildIndex == -1)
|
if (this.context.waitingForTab || this.wildIndex == -1)
|
||||||
this.complete(true, true);
|
this.complete(true, true);
|
||||||
|
|
||||||
this.tabs.push([reverse, wildmode || options["wildmode"]]);
|
this.tabs.push([count, wildmode || options["wildmode"]]);
|
||||||
if (this.waiting)
|
if (this.waiting)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (this.tabs.length) {
|
while (this.tabs.length) {
|
||||||
[reverse, this.wildtypes] = this.tabs.shift();
|
[count, this.wildtypes] = this.tabs.shift();
|
||||||
|
|
||||||
this.wildIndex = Math.min(this.wildIndex, this.wildtypes.length - 1);
|
this.wildIndex = Math.min(this.wildIndex, this.wildtypes.length - 1);
|
||||||
switch (this.wildtype.replace(/.*:/, "")) {
|
switch (this.wildtype.replace(/.*:/, "")) {
|
||||||
@@ -1319,7 +1332,7 @@ var CommandLine = Module("commandline", {
|
|||||||
}
|
}
|
||||||
// Fallthrough
|
// Fallthrough
|
||||||
case "full":
|
case "full":
|
||||||
this.select(reverse ? this.UP : this.DOWN);
|
this.select(count < 0 ? this.UP : this.DOWN, Math.abs(count));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1510,13 +1523,13 @@ var CommandLine = Module("commandline", {
|
|||||||
bind(["<A-Tab>", "<Tab>"], "Select the next matching completion item",
|
bind(["<A-Tab>", "<Tab>"], "Select the next matching completion item",
|
||||||
function ({ keypressEvents, self }) {
|
function ({ keypressEvents, self }) {
|
||||||
dactyl.assert(self.completions);
|
dactyl.assert(self.completions);
|
||||||
self.completions.tabTimer.tell(keypressEvents[0]);
|
self.completions.onTab(keypressEvents[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
bind(["<A-S-Tab>", "<S-Tab>"], "Select the previous matching completion item",
|
bind(["<A-S-Tab>", "<S-Tab>"], "Select the previous matching completion item",
|
||||||
function ({ keypressEvents, self }) {
|
function ({ keypressEvents, self }) {
|
||||||
dactyl.assert(self.completions);
|
dactyl.assert(self.completions);
|
||||||
self.completions.tabTimer.tell(keypressEvents[0]);
|
self.completions.onTab(keypressEvents[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
bind(["<BS>", "<C-h>"], "Delete the previous character",
|
bind(["<BS>", "<C-h>"], "Delete the previous character",
|
||||||
@@ -1585,25 +1598,339 @@ var CommandLine = Module("commandline", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list which is used for the completion box (and QuickFix window in
|
* The list which is used for the completion box.
|
||||||
* future).
|
|
||||||
*
|
*
|
||||||
* @param {string} id The id of the iframe which will display the list. It
|
* @param {string} id The id of the iframe which will display the list. It
|
||||||
* must be in its own container element, whose height it will update as
|
* must be in its own container element, whose height it will update as
|
||||||
* necessary.
|
* necessary.
|
||||||
*/
|
*/
|
||||||
var ItemList = Class("ItemList", {
|
|
||||||
init: function init(id) {
|
|
||||||
this._completionElements = [];
|
|
||||||
|
|
||||||
var iframe = document.getElementById(id);
|
var NewItemList = Class("ItemList", {
|
||||||
|
CONTEXT_LINES: 3,
|
||||||
|
|
||||||
|
init: function init(frame) {
|
||||||
|
this.frame = frame;
|
||||||
|
|
||||||
|
this.doc = frame.contentDocument;
|
||||||
|
this.win = frame.contentWindow;
|
||||||
|
this.body = this.doc.body;
|
||||||
|
this.container = frame.parentNode;
|
||||||
|
|
||||||
|
highlight.highlightNode(this.doc.body, "Comp");
|
||||||
|
|
||||||
|
this._resize = Timer(20, 400, function _resize() {
|
||||||
|
if (this.visible)
|
||||||
|
this.resize();
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
get rootXML() <e4x>
|
||||||
|
<div highlight="Normal" style="white-space: nowrap">
|
||||||
|
<div key="wrapper">
|
||||||
|
<div highlight="Completions" key="noCompletions"><span highlight="Title">{_("completion.noCompletions")}</span></div>
|
||||||
|
<div key="completions"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div highlight="Completions">{
|
||||||
|
template.map(util.range(0, options["maxitems"] * 2), function (i)
|
||||||
|
<div highlight="CompItem NonText"><li>~</li></div>)
|
||||||
|
}</div>
|
||||||
|
</div>
|
||||||
|
</e4x>.elements(),
|
||||||
|
|
||||||
|
get visible() !this.container.collapsed,
|
||||||
|
set visible(val) this.container.collapsed = !val,
|
||||||
|
|
||||||
|
get activeGroups() this.context.contextList
|
||||||
|
.filter(function (c) c.message || c.incomplete
|
||||||
|
|| c.hasItems && c.items.length)
|
||||||
|
.map(this.getGroup, this),
|
||||||
|
|
||||||
|
open: function open(context) {
|
||||||
|
util.dump("\n\n\n\n");
|
||||||
|
util.dump("OPEN()");
|
||||||
|
this.context = context;
|
||||||
|
this.nodes = {x:1};
|
||||||
|
this.maxItems = options["maxitems"];
|
||||||
|
|
||||||
|
DOM(this.rootXML, this.doc, this.nodes)
|
||||||
|
.appendTo(DOM(this.body).empty());
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
this.visible = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
update: function update() {
|
||||||
|
util.dump("\n\n");
|
||||||
|
util.dump("UPDATE()");
|
||||||
|
DOM(this.nodes.completions).empty();
|
||||||
|
|
||||||
|
let groups = this.activeGroups;
|
||||||
|
let container = DOM(this.nodes.completions);
|
||||||
|
for each (let group in groups) {
|
||||||
|
group.reset();
|
||||||
|
container.append(group.nodes.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
DOM(this.nodes.noCompletions).toggle(!groups.length);
|
||||||
|
|
||||||
|
this.select(groups[0] && groups[0].context, null);
|
||||||
|
|
||||||
|
this._resize.tell();
|
||||||
|
},
|
||||||
|
|
||||||
|
draw: function draw() {
|
||||||
|
util.dump("DRAW()");
|
||||||
|
for each (let group in this.activeGroups)
|
||||||
|
group.draw();
|
||||||
|
|
||||||
|
// We need to collect all of the rescrolling functions in
|
||||||
|
// one go, as the height calculation that they need to do
|
||||||
|
// would force a reflow after each DOM modification.
|
||||||
|
this.activeGroups.filter(function (g) !g.collapsed)
|
||||||
|
.map(function (g) g.rescrollFunc)
|
||||||
|
.forEach(function (f) f());
|
||||||
|
},
|
||||||
|
|
||||||
|
minHeight: 0,
|
||||||
|
resize: function resize() {
|
||||||
|
util.dump("RESIZE()");
|
||||||
|
let { completions, root } = this.nodes;
|
||||||
|
|
||||||
|
if (!this.visible)
|
||||||
|
root.style.minWidth = document.getElementById("dactyl-commandline").scrollWidth + "px";
|
||||||
|
|
||||||
|
this.minHeight = Math.max(this.minHeight,
|
||||||
|
this.win.scrollY + DOM(completions).rect.bottom);
|
||||||
|
|
||||||
|
if (!this.visible)
|
||||||
|
root.style.minWidth = "";
|
||||||
|
|
||||||
|
// FIXME: Belongs elsewhere.
|
||||||
|
mow.resize(false, Math.max(0, this.minHeight - this.container.height));
|
||||||
|
|
||||||
|
this.container.height = this.minHeight;
|
||||||
|
this.container.height -= mow.spaceNeeded;
|
||||||
|
mow.resize(false);
|
||||||
|
this.timeout(function () {
|
||||||
|
this.container.height -= mow.spaceNeeded;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
select: function select(context, index, position) {
|
||||||
|
util.dump("SELECT()");
|
||||||
|
let group = this.getGroup(context);
|
||||||
|
|
||||||
|
if (this.selectedGroup && (!group || group != this.selectedGroup))
|
||||||
|
this.selectedGroup.selectedIdx = null;
|
||||||
|
|
||||||
|
this.selectedGroup = group;
|
||||||
|
|
||||||
|
if (group)
|
||||||
|
group.selectedIdx = index;
|
||||||
|
|
||||||
|
if (position != null)
|
||||||
|
this.selectionPosition = position;
|
||||||
|
|
||||||
|
let groups = this.activeGroups;
|
||||||
|
if (groups.length) {
|
||||||
|
group = group || groups[0];
|
||||||
|
let idx = groups.indexOf(group);
|
||||||
|
|
||||||
|
let count = this.maxItems;
|
||||||
|
group.count = Math.min((group.selectedIdx || 0) + this.CONTEXT_LINES,
|
||||||
|
group.itemCount, count);
|
||||||
|
count -= group.count;
|
||||||
|
|
||||||
|
for (let i = idx - 1; i >= 0; i--) {
|
||||||
|
let group = groups[i];
|
||||||
|
group.count = Math.min(group.itemCount, count);
|
||||||
|
count -= group.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
let n = group.count;
|
||||||
|
group.count = Math.min(group.count + count, group.itemCount);
|
||||||
|
count -= group.count - n;
|
||||||
|
|
||||||
|
for (let i = idx + 1; i < groups.length; i++) {
|
||||||
|
let group = groups[i];
|
||||||
|
group.count = Math.min(group.itemCount, count);
|
||||||
|
count -= group.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let [i, group] in Iterator(groups)) {
|
||||||
|
group.collapsed = group.count == 0;
|
||||||
|
if (i < idx)
|
||||||
|
group.range = ItemList.Range(group.itemCount - group.count,
|
||||||
|
group.itemCount);
|
||||||
|
else if (i > idx)
|
||||||
|
group.range = ItemList.Range(0, group.count);
|
||||||
|
else {
|
||||||
|
let end = Math.max(group.count,
|
||||||
|
Math.min(group.selectedIdx + this.CONTEXT_LINES,
|
||||||
|
group.itemCount));
|
||||||
|
group.range = ItemList.Range(end - group.count, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.draw();
|
||||||
|
},
|
||||||
|
|
||||||
|
selectItem: function selectItem(idx) {
|
||||||
|
if (idx != null)
|
||||||
|
for each (var group in this.activeGroups) {
|
||||||
|
if (idx < group.itemCount)
|
||||||
|
break;
|
||||||
|
idx -= group.itemCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.select(group && group.context, idx);
|
||||||
|
},
|
||||||
|
|
||||||
|
getGroup: function getGroup(context) context &&
|
||||||
|
context.getCache("itemlist-group", bind("Group", ItemList, this, context))
|
||||||
|
}, {
|
||||||
|
WAITING_MESSAGE: _("completion.generating"),
|
||||||
|
|
||||||
|
Group: Class("ItemList.Group", {
|
||||||
|
init: function init(parent, context) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.context = context;
|
||||||
|
},
|
||||||
|
|
||||||
|
get rootXML()
|
||||||
|
<div key="root" highlight="CompGroup">
|
||||||
|
<div highlight="Completions">
|
||||||
|
{ this.context.createRow(this.context.title || [], "CompTitle") }
|
||||||
|
</div>
|
||||||
|
<div highlight="CompTitleSep"/>
|
||||||
|
<div key="contents">
|
||||||
|
<div key="up" highlight="CompLess"/>
|
||||||
|
<div key="message" highlight="CompMsg">{this.context.message}</div>
|
||||||
|
<div key="itemsContainer" class="completion-items-container">
|
||||||
|
<div key="items" highlight="Completions"/>
|
||||||
|
</div>
|
||||||
|
<div key="waiting" highlight="CompMsg">{ItemList.WAITING_MESSAGE}</div>
|
||||||
|
<div key="down" highlight="CompMore"/>
|
||||||
|
</div>
|
||||||
|
</div>,
|
||||||
|
|
||||||
|
get doc() this.parent.doc,
|
||||||
|
get win() this.parent.win,
|
||||||
|
get maxItems() this.parent.maxItems,
|
||||||
|
|
||||||
|
get itemCount() this.context.items.length,
|
||||||
|
|
||||||
|
get rescrollFunc() {
|
||||||
|
let container = this.nodes.itemsContainer;
|
||||||
|
let pos = DOM(container).rect.top;
|
||||||
|
let start = DOM(this.getItem(this.range.start)).rect.top;
|
||||||
|
let height = DOM(this.getItem(this.range.end - 1)).rect.bottom - start || 0;
|
||||||
|
let scroll = start + container.scrollTop - pos;
|
||||||
|
return function () {
|
||||||
|
container.scrollTop = scroll;
|
||||||
|
container.style.height = height + "px";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
draw: function draw() {
|
||||||
|
util.dump("draw(" + [this.collapsed, this.itemCount, this.count] + ") [" +
|
||||||
|
(!this.collapsed && [this.range.start, this.range.end]) + ") [" +
|
||||||
|
[this.generatedRange.start,
|
||||||
|
this.generatedRange.end] + ") " +
|
||||||
|
(!this.collapsed && this.generatedRange.contains(this.range)));
|
||||||
|
|
||||||
|
DOM(this.nodes.contents).toggle(!this.collapsed);
|
||||||
|
if (this.collapsed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DOM(this.nodes.message).toggle(this.context.message && this.range.start == 0);
|
||||||
|
DOM(this.nodes.waiting).toggle(this.context.incomplete && this.range.end < this.itemCount);
|
||||||
|
DOM(this.nodes.up).toggle(this.range.start > 0);
|
||||||
|
DOM(this.nodes.down).toggle(this.range.end < this.itemCount);
|
||||||
|
|
||||||
|
if (!this.generatedRange.contains(this.range)) {
|
||||||
|
if (this.generatedRange.end == 0)
|
||||||
|
var [start, end] = this.range;
|
||||||
|
else {
|
||||||
|
start = this.range.start - (this.range.start <= this.generatedRange.start
|
||||||
|
? this.maxItems / 2 : 0);
|
||||||
|
end = this.range.end + (this.range.end > this.generatedRange.end
|
||||||
|
? this.maxItems / 2 : 0);
|
||||||
|
}
|
||||||
|
util.dump(" refill [" + [start,end] + ")");
|
||||||
|
|
||||||
|
let range = ItemList.Range(Math.max(0, start), Math.min(this.itemCount, end));
|
||||||
|
|
||||||
|
let first;
|
||||||
|
for (let [i, row] in this.context.getRows(this.generatedRange.start,
|
||||||
|
this.generatedRange.end,
|
||||||
|
this.doc))
|
||||||
|
if (!range.contains(i))
|
||||||
|
DOM(row).remove();
|
||||||
|
else if (!first)
|
||||||
|
first = row;
|
||||||
|
|
||||||
|
let container = DOM(this.nodes.items);
|
||||||
|
let before = first ? DOM(first).closure.before
|
||||||
|
: DOM(this.nodes.items).closure.append;
|
||||||
|
|
||||||
|
for (let [i, row] in this.context.getRows(range.start, range.end,
|
||||||
|
this.doc))
|
||||||
|
if (i < this.generatedRange.start)
|
||||||
|
before(row);
|
||||||
|
else if (i >= this.generatedRange.end)
|
||||||
|
container.append(row);
|
||||||
|
|
||||||
|
this.generatedRange = range;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
reset: function reset() {
|
||||||
|
this.nodes = {};
|
||||||
|
this.generatedRange = ItemList.Range(0, 0);
|
||||||
|
|
||||||
|
DOM.fromXML(this.rootXML, this.doc, this.nodes);
|
||||||
|
},
|
||||||
|
|
||||||
|
getItem: function getItem(idx) this.context.getRow(idx),
|
||||||
|
|
||||||
|
get selectedItem() this.getItem(this._selectedIdx),
|
||||||
|
|
||||||
|
get selectedIdx() this._selectedIdx,
|
||||||
|
set selectedIdx(idx) {
|
||||||
|
if (this.selectedItem)
|
||||||
|
DOM(this.selectedItem).attr("selected", null);
|
||||||
|
|
||||||
|
this._selectedIdx = idx;
|
||||||
|
|
||||||
|
if (this.selectedItem)
|
||||||
|
DOM(this.selectedItem).attr("selected", true);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
Range: Class.Memoize(function () {
|
||||||
|
let Range = Struct("ItemList.Range", "start", "end");
|
||||||
|
update(Range.prototype, {
|
||||||
|
contains: function contains(idx)
|
||||||
|
typeof idx == "number" ? idx >= this.start && idx < this.end
|
||||||
|
: this.contains(idx.start) &&
|
||||||
|
idx.end >= this.start && idx.end <= this.end
|
||||||
|
});
|
||||||
|
return Range;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
var ItemList = Class("ItemList", {
|
||||||
|
init: function init(iframe) {
|
||||||
|
this._completionElements = [];
|
||||||
|
|
||||||
this._doc = iframe.contentDocument;
|
this._doc = iframe.contentDocument;
|
||||||
this._win = iframe.contentWindow;
|
this._win = iframe.contentWindow;
|
||||||
this._container = iframe.parentNode;
|
this._container = iframe.parentNode;
|
||||||
|
|
||||||
this._doc.documentElement.id = id + "-top";
|
this._doc.documentElement.id = iframe.id + "-top";
|
||||||
this._doc.body.id = id + "-content";
|
this._doc.body.id = iframe.id + "-content";
|
||||||
this._doc.body.className = iframe.className + "-content";
|
this._doc.body.className = iframe.className + "-content";
|
||||||
this._doc.body.appendChild(this._doc.createTextNode(""));
|
this._doc.body.appendChild(this._doc.createTextNode(""));
|
||||||
this._doc.body.style.borderTop = "1px solid black"; // FIXME: For cases where completions/MOW are shown at once, or ls=0. Should use :highlight.
|
this._doc.body.style.borderTop = "1px solid black"; // FIXME: For cases where completions/MOW are shown at once, or ls=0. Should use :highlight.
|
||||||
@@ -1647,7 +1974,7 @@ var ItemList = Class("ItemList", {
|
|||||||
|
|
||||||
_init: function _init() {
|
_init: function _init() {
|
||||||
this._div = this._dom(
|
this._div = this._dom(
|
||||||
<div class="ex-command-output" highlight="Normal" style="white-space: nowrap">
|
<div highlight="CommandOutput Normal" style="white-space: nowrap">
|
||||||
<div key="wrapper">
|
<div key="wrapper">
|
||||||
<div highlight="Completions" key="noCompletions"><span highlight="Title">{_("completion.noCompletions")}</span></div>
|
<div highlight="Completions" key="noCompletions"><span highlight="Title">{_("completion.noCompletions")}</span></div>
|
||||||
<div key="completions"/>
|
<div key="completions"/>
|
||||||
@@ -1676,7 +2003,9 @@ var ItemList = Class("ItemList", {
|
|||||||
<div highlight="CompTitleSep"/>
|
<div highlight="CompTitleSep"/>
|
||||||
<div key="message" highlight="CompMsg"/>
|
<div key="message" highlight="CompMsg"/>
|
||||||
<div key="up" highlight="CompLess"/>
|
<div key="up" highlight="CompLess"/>
|
||||||
|
<div key="itemsContainer">
|
||||||
<div key="items" highlight="Completions"/>
|
<div key="items" highlight="Completions"/>
|
||||||
|
</div>
|
||||||
<div key="waiting" highlight="CompMsg">{ItemList.WAITING_MESSAGE}</div>
|
<div key="waiting" highlight="CompMsg">{ItemList.WAITING_MESSAGE}</div>
|
||||||
<div key="down" highlight="CompMore"/>
|
<div key="down" highlight="CompMore"/>
|
||||||
</div>, context.cache.nodes);
|
</div>, context.cache.nodes);
|
||||||
@@ -1776,7 +2105,7 @@ var ItemList = Class("ItemList", {
|
|||||||
get visible() !this._container.collapsed,
|
get visible() !this._container.collapsed,
|
||||||
set visible(val) this._container.collapsed = !val,
|
set visible(val) this._container.collapsed = !val,
|
||||||
|
|
||||||
reset: function reset(brief) {
|
update: function reset(brief) {
|
||||||
this._startIndex = this._endIndex = this._selIndex = -1;
|
this._startIndex = this._endIndex = this._selIndex = -1;
|
||||||
this._div = null;
|
this._div = null;
|
||||||
if (!brief)
|
if (!brief)
|
||||||
@@ -1787,20 +2116,22 @@ var ItemList = Class("ItemList", {
|
|||||||
setItems: function setItems(newItems, selectedItem) {
|
setItems: function setItems(newItems, selectedItem) {
|
||||||
if (this._selItem > -1)
|
if (this._selItem > -1)
|
||||||
this._getCompletion(this._selItem).removeAttribute("selected");
|
this._getCompletion(this._selItem).removeAttribute("selected");
|
||||||
|
|
||||||
if (this._container.collapsed) {
|
if (this._container.collapsed) {
|
||||||
this._minHeight = 0;
|
this._minHeight = 0;
|
||||||
this._container.height = 0;
|
this._container.height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._startIndex = this._endIndex = this._selIndex = -1;
|
this._startIndex = this._endIndex = this._selIndex = -1;
|
||||||
this._items = newItems;
|
this._items = newItems;
|
||||||
this.reset(true);
|
this.update(true);
|
||||||
if (typeof selectedItem == "number") {
|
if (typeof selectedItem == "number") {
|
||||||
this.selectItem(selectedItem);
|
this.selectItem(selectedItem);
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
get open() this.closure.setItems,
|
||||||
|
|
||||||
// select index, refill list if necessary
|
|
||||||
selectItem: function selectItem(index) {
|
selectItem: function selectItem(index) {
|
||||||
//let now = Date.now();
|
//let now = Date.now();
|
||||||
|
|
||||||
@@ -1848,7 +2179,7 @@ var ItemList = Class("ItemList", {
|
|||||||
|
|
||||||
onKeyPress: function onKeyPress(event) false
|
onKeyPress: function onKeyPress(event) false
|
||||||
}, {
|
}, {
|
||||||
WAITING_MESSAGE: _("completion.generating")
|
WAITING_MESSAGE: _("completion.generating"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// vim: set fdm=marker sw=4 ts=4 et:
|
// vim: set fdm=marker sw=4 ts=4 et:
|
||||||
|
|||||||
@@ -21,11 +21,9 @@ var MOW = Module("mow", {
|
|||||||
if (modes.have(modes.OUTPUT_MULTILINE)) {
|
if (modes.have(modes.OUTPUT_MULTILINE)) {
|
||||||
this.resize(true);
|
this.resize(true);
|
||||||
|
|
||||||
if (options["more"] && this.canScroll(1)) {
|
if (options["more"] && this.canScroll(1))
|
||||||
// start the last executed command's output at the top of the screen
|
// start the last executed command's output at the top of the screen
|
||||||
let elements = this.document.getElementsByClassName("ex-command-output");
|
DOM(this.document.body.lastElementChild).scrollIntoView(true);
|
||||||
DOM(elements[elements.length - 1]).scrollIntoView(true);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
this.body.scrollTop = this.body.scrollHeight;
|
this.body.scrollTop = this.body.scrollHeight;
|
||||||
|
|
||||||
@@ -122,10 +120,12 @@ var MOW = Module("mow", {
|
|||||||
// after interpolated data.
|
// after interpolated data.
|
||||||
XML.ignoreWhitespace = XML.prettyPrinting = false;
|
XML.ignoreWhitespace = XML.prettyPrinting = false;
|
||||||
|
|
||||||
|
highlightGroup = "CommandOutput " + (highlight || "");
|
||||||
|
|
||||||
if (isObject(data) && !isinstance(data, _)) {
|
if (isObject(data) && !isinstance(data, _)) {
|
||||||
this.lastOutput = null;
|
this.lastOutput = null;
|
||||||
|
|
||||||
var output = DOM(<div class="ex-command-output" style="white-space: nowrap" highlight={highlightGroup}/>,
|
var output = DOM(<div style="white-space: nowrap" highlight={highlightGroup}/>,
|
||||||
this.document);
|
this.document);
|
||||||
data.document = this.document;
|
data.document = this.document;
|
||||||
try {
|
try {
|
||||||
@@ -139,7 +139,7 @@ var MOW = Module("mow", {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let style = isString(data) ? "pre-wrap" : "nowrap";
|
let style = isString(data) ? "pre-wrap" : "nowrap";
|
||||||
this.lastOutput = <div class="ex-command-output" style={"white-space: " + style} highlight={highlightGroup}>{data}</div>;
|
this.lastOutput = <div style={"white-space: " + style} highlight={highlightGroup}>{data}</div>;
|
||||||
|
|
||||||
var output = DOM(this.lastOutput, this.document);
|
var output = DOM(this.lastOutput, this.document);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -868,6 +868,7 @@ Class.Memoize = function Memoize(getter, wait)
|
|||||||
let done = false;
|
let done = false;
|
||||||
|
|
||||||
if (wait)
|
if (wait)
|
||||||
|
// Crazy, yeah, I know. -- Kris
|
||||||
this.get = function replace() {
|
this.get = function replace() {
|
||||||
let obj = this.instance || this;
|
let obj = this.instance || this;
|
||||||
Object.defineProperty(obj, key, {
|
Object.defineProperty(obj, key, {
|
||||||
@@ -892,7 +893,7 @@ Class.Memoize = function Memoize(getter, wait)
|
|||||||
return this[key];
|
return this[key];
|
||||||
};
|
};
|
||||||
else
|
else
|
||||||
this.get = function replace() {
|
this.get = function g_Memoize() {
|
||||||
let obj = this.instance || this;
|
let obj = this.instance || this;
|
||||||
try {
|
try {
|
||||||
Class.replaceProperty(obj, key, null);
|
Class.replaceProperty(obj, key, null);
|
||||||
@@ -903,7 +904,7 @@ Class.Memoize = function Memoize(getter, wait)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.set = function replace(val) Class.replaceProperty(this.instance || this, val);
|
this.set = function s_Memoize(val) Class.replaceProperty(this.instance || this, key, val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1227,6 +1228,8 @@ var StructBase = Class("StructBase", Array, {
|
|||||||
this[i] = arguments[i];
|
this[i] = arguments[i];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get toStringParams() this,
|
||||||
|
|
||||||
clone: function struct_clone() this.constructor.apply(null, this.slice()),
|
clone: function struct_clone() this.constructor.apply(null, this.slice()),
|
||||||
|
|
||||||
closure: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "closure")),
|
closure: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "closure")),
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ var Buffer = Module("Buffer", {
|
|||||||
* @param {Node} elem The element to focus.
|
* @param {Node} elem The element to focus.
|
||||||
*/
|
*/
|
||||||
focusElement: function focusElement(elem) {
|
focusElement: function focusElement(elem) {
|
||||||
let { dactyl } = this.modules;
|
let { Editor, dactyl } = this.modules;
|
||||||
|
|
||||||
let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem;
|
let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem;
|
||||||
overlay.setData(elem, "focus-allowed", true);
|
overlay.setData(elem, "focus-allowed", true);
|
||||||
|
|||||||
@@ -633,24 +633,32 @@ var CompletionContext = Class("CompletionContext", {
|
|||||||
return iter.map(util.range(start, end, step), function (i) items[i]);
|
return iter.map(util.range(start, end, step), function (i) items[i]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getRow: function getRow(idx) this.cache.rows && this.cache.rows[idx],
|
||||||
|
|
||||||
getRows: function getRows(start, end, doc) {
|
getRows: function getRows(start, end, doc) {
|
||||||
let self = this;
|
let self = this;
|
||||||
let items = this.items;
|
let items = this.items;
|
||||||
let cache = this.cache.rows;
|
let cache = this.cache.rows;
|
||||||
let step = start > end ? -1 : 1;
|
let step = start > end ? -1 : 1;
|
||||||
|
|
||||||
start = Math.max(0, start || 0);
|
start = Math.max(0, start || 0);
|
||||||
end = Math.min(items.length, end != null ? end : items.length);
|
end = Math.min(items.length, end != null ? end : items.length);
|
||||||
for (let i in util.range(start, end, step))
|
|
||||||
|
for (let i in util.range(start, end, step)) {
|
||||||
|
if (!cache[i])
|
||||||
try {
|
try {
|
||||||
yield [i, cache[i] = cache[i] || util.xmlToDom(self.createRow(items[i]), doc)];
|
cache[i] = util.xmlToDom(self.createRow(items[i]), doc);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
util.reportError(e);
|
util.reportError(e);
|
||||||
yield [i, cache[i] = cache[i] || util.xmlToDom(
|
cache[i] = util.xmlToDom(
|
||||||
<div highlight="CompItem" style="white-space: nowrap">
|
<div highlight="CompItem" style="white-space: nowrap">
|
||||||
<li highlight="CompResult">{items[i].text} </li>
|
<li highlight="CompResult">{items[i].text} </li>
|
||||||
<li highlight="CompDesc ErrorMsg">{e} </li>
|
<li highlight="CompDesc ErrorMsg">{e} </li>
|
||||||
</div>, doc)];
|
</div>, doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield [i, cache[i]];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ var Contexts = Module("contexts", {
|
|||||||
|
|
||||||
cleanup: function () {
|
cleanup: function () {
|
||||||
for each (let module in this.pluginModules)
|
for each (let module in this.pluginModules)
|
||||||
util.trapErrors("cleanup", module);
|
util.trapErrors("unload", module);
|
||||||
|
|
||||||
this.pluginModules = {};
|
this.pluginModules = {};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -36,10 +36,13 @@ function BooleanAttribute(attr) ({
|
|||||||
* change in the near future.
|
* change in the near future.
|
||||||
*/
|
*/
|
||||||
var DOM = Class("DOM", {
|
var DOM = Class("DOM", {
|
||||||
init: function init(val, context) {
|
init: function init(val, context, nodes) {
|
||||||
let self;
|
let self;
|
||||||
let length = 0;
|
let length = 0;
|
||||||
|
|
||||||
|
if (nodes)
|
||||||
|
this.nodes = nodes;
|
||||||
|
|
||||||
if (context instanceof Ci.nsIDOMDocument)
|
if (context instanceof Ci.nsIDOMDocument)
|
||||||
this.document = context;
|
this.document = context;
|
||||||
|
|
||||||
@@ -48,7 +51,7 @@ var DOM = Class("DOM", {
|
|||||||
|
|
||||||
if (val == null)
|
if (val == null)
|
||||||
;
|
;
|
||||||
else if (typeof val == "xml")
|
else if (typeof val == "xml" && context instanceof Ci.nsIDOMDocument)
|
||||||
this[length++] = DOM.fromXML(val, context, this.nodes);
|
this[length++] = DOM.fromXML(val, context, this.nodes);
|
||||||
else if (val instanceof Ci.nsIDOMNode || val instanceof Ci.nsIDOMWindow)
|
else if (val instanceof Ci.nsIDOMNode || val instanceof Ci.nsIDOMWindow)
|
||||||
this[length++] = val;
|
this[length++] = val;
|
||||||
@@ -58,6 +61,8 @@ var DOM = Class("DOM", {
|
|||||||
else if ("__iterator__" in val || isinstance(val, ["Iterator", "Generator"]))
|
else if ("__iterator__" in val || isinstance(val, ["Iterator", "Generator"]))
|
||||||
for (let elem in val)
|
for (let elem in val)
|
||||||
this[length++] = elem;
|
this[length++] = elem;
|
||||||
|
else
|
||||||
|
this[length++] = val;
|
||||||
|
|
||||||
this.length = length;
|
this.length = length;
|
||||||
return self || this;
|
return self || this;
|
||||||
@@ -130,19 +135,22 @@ var DOM = Class("DOM", {
|
|||||||
}, self || this);
|
}, self || this);
|
||||||
|
|
||||||
let dom = this;
|
let dom = this;
|
||||||
function munge(val) {
|
function munge(val, container, idx) {
|
||||||
if (val instanceof Ci.nsIDOMRange)
|
if (val instanceof Ci.nsIDOMRange)
|
||||||
return val.extractContents();
|
return val.extractContents();
|
||||||
if (val instanceof Ci.nsIDOMNode)
|
if (val instanceof Ci.nsIDOMNode)
|
||||||
return val;
|
return val;
|
||||||
|
|
||||||
if (typeof val == "xml")
|
if (typeof val == "xml") {
|
||||||
val = dom.constructor(val, dom.document);
|
val = dom.constructor(val, dom.document);
|
||||||
|
if (container)
|
||||||
|
container[idx] = val[0];
|
||||||
|
}
|
||||||
|
|
||||||
if (isObject(val) && "length" in val) {
|
if (isObject(val) && "length" in val) {
|
||||||
let frag = dom.document.createDocumentFragment();
|
let frag = dom.document.createDocumentFragment();
|
||||||
for (let i = 0; i < val.length; i++)
|
for (let i = 0; i < val.length; i++)
|
||||||
frag.appendChild(munge(val[i]));
|
frag.appendChild(munge(val[i], val, i));
|
||||||
return frag;
|
return frag;
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ var FailedAssertion = Class("FailedAssertion", ErrorBase, {
|
|||||||
noTrace: true
|
noTrace: true
|
||||||
});
|
});
|
||||||
|
|
||||||
var Point = Struct("x", "y");
|
var Point = Struct("Point", "x", "y");
|
||||||
|
|
||||||
var wrapCallback = function wrapCallback(fn, isEvent) {
|
var wrapCallback = function wrapCallback(fn, isEvent) {
|
||||||
if (!fn.wrapper)
|
if (!fn.wrapper)
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ input[type=file][dactyl|highlight~=HintElem] {
|
|||||||
line-height: 1.5em !important;
|
line-height: 1.5em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.completion-items-container {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.td-span {
|
.td-span {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
@@ -191,11 +195,9 @@ statusbarpanel {
|
|||||||
|
|
||||||
/* MOW */
|
/* MOW */
|
||||||
|
|
||||||
.dactyl-completions,
|
#dactyl-commandline-prompt *,
|
||||||
#dactyl-multiline-output,
|
#dactyl-commandline-command {
|
||||||
#dactyl-multiline-input {
|
font: inherit;
|
||||||
background-color: white;
|
|
||||||
color: black;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dactyl-completions-content,
|
.dactyl-completions-content,
|
||||||
@@ -206,11 +208,6 @@ statusbarpanel {
|
|||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#dactyl-commandline-prompt *,
|
|
||||||
#dactyl-commandline-command {
|
|
||||||
font: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dactyl-completions-content table,
|
.dactyl-completions-content table,
|
||||||
#dactyl-multiline-output-content table {
|
#dactyl-multiline-output-content table {
|
||||||
white-space: inherit;
|
white-space: inherit;
|
||||||
|
|||||||
@@ -84,6 +84,9 @@ CmdInput;.dactyl-commandline-command
|
|||||||
CmdOutput /* The output of commands executed by <ex>:run</ex> */ \
|
CmdOutput /* The output of commands executed by <ex>:run</ex> */ \
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
|
|
||||||
|
Comp;;;FontFixed,Normal /* The completion window */ \
|
||||||
|
margin: 0; border-top: 1px solid black;
|
||||||
|
|
||||||
CompGroup /* Item group in completion output */
|
CompGroup /* Item group in completion output */
|
||||||
CompGroup:not(:first-of-type) margin-top: .5em;
|
CompGroup:not(:first-of-type) margin-top: .5em;
|
||||||
CompGroup:last-of-type padding-bottom: 1.5ex;
|
CompGroup:last-of-type padding-bottom: 1.5ex;
|
||||||
|
|||||||
Reference in New Issue
Block a user