mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-23 10:57:58 +01:00
More completion stuff
This commit is contained in:
@@ -43,13 +43,18 @@ function CompletionContext(editor, name, offset)
|
|||||||
name = parent.name + "/" + name;
|
name = parent.name + "/" + name;
|
||||||
this.contexts = parent.contexts;
|
this.contexts = parent.contexts;
|
||||||
if (name in this.contexts)
|
if (name in this.contexts)
|
||||||
return this.contexts[name];
|
{
|
||||||
|
let self = this.contexts[name];
|
||||||
|
self.offset = parent.offset + (offset || 0);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
this.contexts[name] = this;
|
this.contexts[name] = this;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.editor = parent.editor;
|
this.editor = parent.editor;
|
||||||
this.offset = parent.offset + (offset || 0);
|
this.offset = parent.offset + (offset || 0);
|
||||||
this.__defineGetter__("tabPressed", function () this.parent.tabPressed);
|
this.__defineGetter__("tabPressed", function () this.parent.tabPressed);
|
||||||
this.__defineGetter__("onUpdate", function () this.parent.onUpdate);
|
this.__defineGetter__("onUpdate", function () this.parent.onUpdate);
|
||||||
|
this.__defineGetter__("value", function () this.parent.value);
|
||||||
this.incomplete = false;
|
this.incomplete = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -94,6 +99,9 @@ CompletionContext.prototype = {
|
|||||||
|
|
||||||
get contextList() [v for ([k, v] in Iterator(this.contexts))],
|
get contextList() [v for ([k, v] in Iterator(this.contexts))],
|
||||||
|
|
||||||
|
get createRow() this._createRow || template.completionRow, // XXX
|
||||||
|
set createRow(createRow) this._createRow = createRow,
|
||||||
|
|
||||||
get filter() this.value.substr(this.offset, this.caret),
|
get filter() this.value.substr(this.offset, this.caret),
|
||||||
|
|
||||||
get items() this._items,
|
get items() this._items,
|
||||||
@@ -104,7 +112,8 @@ CompletionContext.prototype = {
|
|||||||
this.onUpdate.call(this);
|
this.onUpdate.call(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
get value() this.editor.rootElement.textContent,
|
get title() this._title || ["Completions"], // XXX
|
||||||
|
set title(val) this._title = val,
|
||||||
|
|
||||||
advance: function (count)
|
advance: function (count)
|
||||||
{
|
{
|
||||||
@@ -154,6 +163,7 @@ CompletionContext.prototype = {
|
|||||||
this.selectionTypes = {};
|
this.selectionTypes = {};
|
||||||
this.tabPressed = false;
|
this.tabPressed = false;
|
||||||
this.offset = 0;
|
this.offset = 0;
|
||||||
|
this.value = this.editor.rootElement.textContent;
|
||||||
//for (let key in (k for ([k, v] in Iterator(self.contexts)) if (v.offset > this.caret)))
|
//for (let key in (k for ([k, v] in Iterator(self.contexts)) if (v.offset > this.caret)))
|
||||||
// delete this.contexts[key];
|
// delete this.contexts[key];
|
||||||
for each (let context in this.contexts)
|
for each (let context in this.contexts)
|
||||||
@@ -294,7 +304,6 @@ function Completion() //{{{
|
|||||||
if (last != undefined) // Escaping the key (without adding quotes), so it matches the escaped completions.
|
if (last != undefined) // Escaping the key (without adding quotes), so it matches the escaped completions.
|
||||||
key = util.escapeString(key.substr(offset), "");
|
key = util.escapeString(key.substr(offset), "");
|
||||||
|
|
||||||
completion.filterString = key;
|
|
||||||
let res = buildLongestStartingSubstring(compl, key);
|
let res = buildLongestStartingSubstring(compl, key);
|
||||||
if (res.length == 0)
|
if (res.length == 0)
|
||||||
{
|
{
|
||||||
@@ -529,7 +538,7 @@ function Completion() //{{{
|
|||||||
cacheKey = str.substring(statement, dot);
|
cacheKey = str.substring(statement, dot);
|
||||||
obj = self.eval(s, cacheKey, obj);
|
obj = self.eval(s, cacheKey, obj);
|
||||||
}
|
}
|
||||||
return [[obj], str.substring(statement, stop + 1)];
|
return [[obj, str.substring(statement, stop + 1)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getObjKey(frame)
|
function getObjKey(frame)
|
||||||
@@ -692,7 +701,6 @@ function Completion() //{{{
|
|||||||
// list = [ [['com1', 'com2'], 'text'], [['com3', 'com4'], 'text'] ]
|
// list = [ [['com1', 'com2'], 'text'], [['com3', 'com4'], 'text'] ]
|
||||||
function buildLongestCommonSubstring(list, filter, favicon)
|
function buildLongestCommonSubstring(list, filter, favicon)
|
||||||
{
|
{
|
||||||
completion.filterString = filter;
|
|
||||||
var filtered = [];
|
var filtered = [];
|
||||||
|
|
||||||
var ignorecase = false;
|
var ignorecase = false;
|
||||||
@@ -1027,13 +1035,13 @@ function Completion() //{{{
|
|||||||
|
|
||||||
environment: function environment(filter)
|
environment: function environment(filter)
|
||||||
{
|
{
|
||||||
let command = liberator.has("Win32") ? "set" : "export";
|
let command = liberator.has("Win32") ? "set" : "env";
|
||||||
let lines = io.system(command).split("\n");
|
let lines = io.system(command).split("\n");
|
||||||
|
|
||||||
lines.splice(lines.length - 1, 1);
|
lines.pop();
|
||||||
|
|
||||||
let vars = lines.map(function (line) {
|
let vars = lines.map(function (line) {
|
||||||
let matches = line.match(/([^=]+)=(.+)/);
|
let matches = line.match(/([^=]+)=(.+)/) || [];
|
||||||
return [matches[1], matches[2]];
|
return [matches[1], matches[2]];
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1044,7 +1052,6 @@ function Completion() //{{{
|
|||||||
ex: function ex(context)
|
ex: function ex(context)
|
||||||
{
|
{
|
||||||
this.filterMap = null;
|
this.filterMap = null;
|
||||||
this.filterString = "";
|
|
||||||
substrings = [];
|
substrings = [];
|
||||||
if (context.filter.indexOf(cacheFilter["ex"]) != 0)
|
if (context.filter.indexOf(cacheFilter["ex"]) != 0)
|
||||||
{
|
{
|
||||||
@@ -1069,7 +1076,6 @@ function Completion() //{{{
|
|||||||
{
|
{
|
||||||
[prefix] = context.filter.match(/^(?:\w*[\s!]|!)\s*/);
|
[prefix] = context.filter.match(/^(?:\w*[\s!]|!)\s*/);
|
||||||
context = context.fork(cmd, prefix.length);
|
context = context.fork(cmd, prefix.length);
|
||||||
this.filterString = context.filter;
|
|
||||||
args = command.parseArgs(context.filter, true);
|
args = command.parseArgs(context.filter, true);
|
||||||
if (args)
|
if (args)
|
||||||
{
|
{
|
||||||
@@ -1220,7 +1226,6 @@ function Completion() //{{{
|
|||||||
// XXX: Move to bookmarks.js?
|
// XXX: Move to bookmarks.js?
|
||||||
searchEngineSuggest: function (context, engineAliases)
|
searchEngineSuggest: function (context, engineAliases)
|
||||||
{
|
{
|
||||||
this.filterString = context.filter;
|
|
||||||
if (!filter)
|
if (!filter)
|
||||||
return [0, []];
|
return [0, []];
|
||||||
|
|
||||||
@@ -1325,7 +1330,6 @@ function Completion() //{{{
|
|||||||
// if the 'complete' argument is passed like "h", it temporarily overrides the complete option
|
// if the 'complete' argument is passed like "h", it temporarily overrides the complete option
|
||||||
url: function url(context, complete)
|
url: function url(context, complete)
|
||||||
{
|
{
|
||||||
this.filterString = context.filter;
|
|
||||||
var numLocationCompletions = 0; // how many async completions did we already return to the caller?
|
var numLocationCompletions = 0; // how many async completions did we already return to the caller?
|
||||||
var start = 0;
|
var start = 0;
|
||||||
var skip = context.filter.match("^.*" + options["urlseparator"]); // start after the last 'urlseparator'
|
var skip = context.filter.match("^.*" + options["urlseparator"]); // start after the last 'urlseparator'
|
||||||
@@ -1339,6 +1343,13 @@ function Completion() //{{{
|
|||||||
b: function (context)
|
b: function (context)
|
||||||
{
|
{
|
||||||
context.title = ["Bookmark", "Title"];
|
context.title = ["Bookmark", "Title"];
|
||||||
|
context.createRow = function (context, item, class)
|
||||||
|
{
|
||||||
|
// FIXME
|
||||||
|
if (class)
|
||||||
|
return template.completionRow(context, item, class);
|
||||||
|
return template.bookmarkItem(item);
|
||||||
|
}
|
||||||
context.items = bookmarks.get(context.filter)
|
context.items = bookmarks.get(context.filter)
|
||||||
},
|
},
|
||||||
l: function (context)
|
l: function (context)
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ function Highlights(name, store, serial)
|
|||||||
NonText color: blue; min-height: 16px; padding-left: 2px;
|
NonText color: blue; min-height: 16px; padding-left: 2px;
|
||||||
|
|
||||||
|
|
||||||
|
CompTitle color: magenta; background: white; font-weight: bold;
|
||||||
CompItem
|
CompItem
|
||||||
CompItem[selected] background: yellow;
|
CompItem[selected] background: yellow;
|
||||||
CompItem>* padding: 0 .5ex;
|
CompItem>* padding: 0 .5ex;
|
||||||
|
|||||||
@@ -32,6 +32,38 @@ const template = {
|
|||||||
return <>{xml}</>;
|
return <>{xml}</>;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
completionRow: function (context, item, class)
|
||||||
|
{
|
||||||
|
let text = item.text || item[0] || "";
|
||||||
|
let description = item.description || item[1] || "";
|
||||||
|
let icon = item.icon || item[2];
|
||||||
|
|
||||||
|
/* Kludge until we have completion contexts. */
|
||||||
|
let map = completion.filterMap;
|
||||||
|
if (map)
|
||||||
|
{
|
||||||
|
text = map[0] ? map[0](text) : text;
|
||||||
|
description = map[1] ? map[1](description) : description;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Move.
|
||||||
|
let filter = context.filter;
|
||||||
|
if (filter)
|
||||||
|
{
|
||||||
|
text = template.highlightFilter(text, filter);
|
||||||
|
description = template.highlightFilter(description, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof icon == "function")
|
||||||
|
icon = icon();
|
||||||
|
|
||||||
|
return <ul class={class || "hl-CompItem"}>
|
||||||
|
<li class="hl-CompIcon">{icon ? <img src={icon}/> : <></>}</li>
|
||||||
|
<li class="hl-CompResult">{text}</li>
|
||||||
|
<li class="hl-CompDesc">{description}</li>
|
||||||
|
</ul>;
|
||||||
|
},
|
||||||
|
|
||||||
// if "processStrings" is true, any passed strings will be surrounded by " and
|
// if "processStrings" is true, any passed strings will be surrounded by " and
|
||||||
// any line breaks are displayed as \n
|
// any line breaks are displayed as \n
|
||||||
highlight: function (arg, processStrings)
|
highlight: function (arg, processStrings)
|
||||||
|
|||||||
137
content/ui.js
137
content/ui.js
@@ -842,7 +842,7 @@ function CommandLine() //{{{
|
|||||||
//if (options.get("wildoptions").has("sort"))
|
//if (options.get("wildoptions").has("sort"))
|
||||||
// completions.items.sort(function (a, b) String.localeCompare(a[0], b[0]));
|
// completions.items.sort(function (a, b) String.localeCompare(a[0], b[0]));
|
||||||
|
|
||||||
completionList.setItems(completionContext.allItems);
|
completionList.setItems(completionContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completions.items.length == 0)
|
if (completions.items.length == 0)
|
||||||
@@ -1243,7 +1243,7 @@ function CommandLine() //{{{
|
|||||||
//if (newCompletions.incompleteResult && newCompletions.items.length == 0)
|
//if (newCompletions.incompleteResult && newCompletions.items.length == 0)
|
||||||
// return;
|
// return;
|
||||||
|
|
||||||
completionList.setItems(newCompletions.items);
|
completionList.setItems(completionContext);
|
||||||
|
|
||||||
// try to keep the old item selected
|
// try to keep the old item selected
|
||||||
if (completionIndex >= 0 && completionIndex < newCompletions.items.length && completionIndex < completions.items.length)
|
if (completionIndex >= 0 && completionIndex < newCompletions.items.length && completionIndex < completions.items.length)
|
||||||
@@ -1314,7 +1314,7 @@ function ItemList(id) //{{{
|
|||||||
doc.body.id = id + "-content";
|
doc.body.id = id + "-content";
|
||||||
doc.body.appendChild(doc.createTextNode(""));
|
doc.body.appendChild(doc.createTextNode(""));
|
||||||
|
|
||||||
var items = [];
|
var items = null;
|
||||||
var startIndex = -1; // The index of the first displayed item
|
var startIndex = -1; // The index of the first displayed item
|
||||||
var endIndex = -1; // The index one *after* the last displayed item
|
var endIndex = -1; // The index one *after* the last displayed item
|
||||||
var selIndex = -1; // The index of the currently selected element
|
var selIndex = -1; // The index of the currently selected element
|
||||||
@@ -1333,40 +1333,6 @@ function ItemList(id) //{{{
|
|||||||
commandline.updateOutputHeight(false);
|
commandline.updateOutputHeight(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move to completions?
|
|
||||||
function createDefaultRow(item, dom)
|
|
||||||
{
|
|
||||||
let { text: text, description: description, icon: icon } = item;
|
|
||||||
/* Kludge until we have completion contexts. */
|
|
||||||
let map = completion.filterMap;
|
|
||||||
if (map)
|
|
||||||
{
|
|
||||||
text = map[0] ? map[0](text) : text;
|
|
||||||
description = map[1] ? map[1](description) : description;
|
|
||||||
}
|
|
||||||
/* Obviously, ItemList shouldn't know or care about this. */
|
|
||||||
let filter = completion.filterString;
|
|
||||||
if (filter)
|
|
||||||
{
|
|
||||||
text = template.highlightFilter(text, filter);
|
|
||||||
description = template.highlightFilter(description, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof icon == "function")
|
|
||||||
icon = icon();
|
|
||||||
|
|
||||||
let row =
|
|
||||||
<ul class="hl-CompItem">
|
|
||||||
<li class="hl-CompIcon">{icon ? <img src={icon}/> : <></>}</li>
|
|
||||||
<li class="hl-CompResult">{text}</li>
|
|
||||||
<li class="hl-CompDesc">{description}</li>
|
|
||||||
</ul>;
|
|
||||||
|
|
||||||
if (dom)
|
|
||||||
return util.xmlToDom(row, doc);
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCompletion(index) completionElements[index - startIndex];
|
function getCompletion(index) completionElements[index - startIndex];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1378,60 +1344,56 @@ function ItemList(id) //{{{
|
|||||||
function fill(offset)
|
function fill(offset)
|
||||||
{
|
{
|
||||||
let diff = offset - startIndex;
|
let diff = offset - startIndex;
|
||||||
if (offset == null || offset - startIndex == 0 || offset < 0 || items.length && offset >= items.length)
|
if (items == null || offset == null || offset - startIndex == 0 || offset < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
startIndex = offset;
|
startIndex = offset;
|
||||||
endIndex = Math.min(startIndex + maxItems, items.length);
|
endIndex = Math.min(startIndex + maxItems, items.allItems.items.length);
|
||||||
|
|
||||||
if (selIndex > -1 && Math.abs(diff) == 1) /* Scroll one position */
|
// do a full refill of the list:
|
||||||
|
XML.ignoreWhitespace = true;
|
||||||
|
let off = 0;
|
||||||
|
function range(context)
|
||||||
{
|
{
|
||||||
let tbody = completionBody;
|
let len = context.items.length;
|
||||||
|
let start = off;
|
||||||
if (diff == 1) /* Scroll down */
|
off += len;
|
||||||
{
|
return util.range(Math.max(offset - start, 0), Math.min(endIndex - start, len));
|
||||||
let item = items[endIndex - 1];
|
|
||||||
let row = "xml" in item ? util.xmlToDom(item.xml, doc) : createDefaultRow(item, true);
|
|
||||||
tbody.removeChild(tbody.firstChild);
|
|
||||||
tbody.appendChild(row);
|
|
||||||
}
|
|
||||||
else /* Scroll up */
|
|
||||||
{
|
|
||||||
let item = items[offset];
|
|
||||||
let row = "xml" in item ? util.xmlToDom(item.xml, doc) : createDefaultRow(item, true);
|
|
||||||
tbody.removeChild(tbody.lastChild);
|
|
||||||
tbody.insertBefore(row, tbody.firstChild);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// do a full refill of the list:
|
|
||||||
XML.ignoreWhitespace = true;
|
|
||||||
let xml = <div class="ex-command-output hl-Normal" style="white-space: nowrap">
|
|
||||||
<span class="hl-Title">Completions:</span>
|
|
||||||
<div class="hl-Completions">
|
|
||||||
{
|
|
||||||
template.map(util.range(offset, endIndex), function (i)
|
|
||||||
"xml" in items[i] ? items[i].xml : createDefaultRow(items[i]))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div class="hl-Completions">
|
|
||||||
{
|
|
||||||
// Hmm. The problem with not making this a CompItem is that
|
|
||||||
// the height and padding aren't the same.
|
|
||||||
template.map(util.range(0, maxItems), function (i)
|
|
||||||
<ul><li class="hl-NonText">~</li></ul>)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>;
|
|
||||||
|
|
||||||
div = util.xmlToDom(xml, doc);
|
let xml = <div class="ex-command-output hl-Normal" style="white-space: nowrap">
|
||||||
completionBody = div.getElementsByClassName("hl-Completions")[0];
|
{
|
||||||
//completionElements = completionBody.childNodes; // Kris: This is broken for things like :dia pr<tab>
|
items.allItems.items.length == 0 &&
|
||||||
completionElements = div.getElementsByClassName("hl-CompItem");
|
<div class="hl-Completions">
|
||||||
doc.body.replaceChild(div, doc.body.firstChild);
|
<span class="hl-Title">No Completions</span>
|
||||||
autoSize();
|
</div> || <></>
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
template.map(items.contextList, function (context) context.hasItems &&
|
||||||
|
<div class="hl-Completions">
|
||||||
|
{ context.createRow(context, context.title || {}, "hl-CompTitle") }
|
||||||
|
{
|
||||||
|
template.map(range(context), function (i) context.createRow(context, context.items[i]))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|| undefined)
|
||||||
|
}
|
||||||
|
<div class="hl-Completions">
|
||||||
|
{
|
||||||
|
// Hmm. The problem with not making this a CompItem is that
|
||||||
|
// the height and padding aren't the same.
|
||||||
|
template.map(util.range(0, maxItems), function (i)
|
||||||
|
<ul><li class="hl-NonText">~</li></ul>)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
div = util.xmlToDom(xml, doc);
|
||||||
|
completionBody = div.getElementsByClassName("hl-Completions")[0];
|
||||||
|
//completionElements = completionBody.childNodes; // Kris: This is broken for things like :dia pr<tab>
|
||||||
|
completionElements = div.getElementsByClassName("hl-CompItem");
|
||||||
|
doc.body.replaceChild(div, doc.body.firstChild);
|
||||||
|
autoSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////}}}
|
/////////////////////////////////////////////////////////////////////////////}}}
|
||||||
@@ -1460,7 +1422,7 @@ function ItemList(id) //{{{
|
|||||||
setItems: function setItems(newItems, selectedItem)
|
setItems: function setItems(newItems, selectedItem)
|
||||||
{
|
{
|
||||||
startIndex = endIndex = selIndex = -1;
|
startIndex = endIndex = selIndex = -1;
|
||||||
items = newItems || [];
|
items = newItems;
|
||||||
if (typeof selectedItem == "number")
|
if (typeof selectedItem == "number")
|
||||||
{
|
{
|
||||||
this.selectItem(selectedItem);
|
this.selectItem(selectedItem);
|
||||||
@@ -1474,7 +1436,8 @@ function ItemList(id) //{{{
|
|||||||
//if (container.collapsed) // fixme
|
//if (container.collapsed) // fixme
|
||||||
// return;
|
// return;
|
||||||
|
|
||||||
if (index == -1 || index == items.length) // wrapped around
|
let len = items.allItems.items.length;
|
||||||
|
if (index == -1 || index == len) // wrapped around
|
||||||
{
|
{
|
||||||
if (selIndex >= 0)
|
if (selIndex >= 0)
|
||||||
getCompletion(selIndex).removeAttribute("selected");
|
getCompletion(selIndex).removeAttribute("selected");
|
||||||
@@ -1491,7 +1454,7 @@ function ItemList(id) //{{{
|
|||||||
else if (index <= startIndex + CONTEXT_LINES)
|
else if (index <= startIndex + CONTEXT_LINES)
|
||||||
newOffset = index - CONTEXT_LINES;
|
newOffset = index - CONTEXT_LINES;
|
||||||
|
|
||||||
newOffset = Math.min(newOffset, items.length - maxItems);
|
newOffset = Math.min(newOffset, len - maxItems);
|
||||||
newOffset = Math.max(newOffset, 0);
|
newOffset = Math.max(newOffset, 0);
|
||||||
|
|
||||||
if (selIndex > -1)
|
if (selIndex > -1)
|
||||||
|
|||||||
@@ -60,13 +60,13 @@ the terms of any one of the MPL, the GPL or the LGPL.
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
display: table;
|
display: table;
|
||||||
}
|
}
|
||||||
.hl-CompItem {
|
.hl-CompItem, .hl-CompTitle {
|
||||||
display: table-row;
|
display: table-row;
|
||||||
}
|
}
|
||||||
.hl-Completions > ul {
|
.hl-Completions > ul {
|
||||||
display: table-row;
|
display: table-row;
|
||||||
}
|
}
|
||||||
.hl-CompItem > * {
|
.hl-CompItem > *, .hl-CompTitle > * {
|
||||||
-moz-binding: url(chrome://liberator/content/bindings.xml#compitem-td);
|
-moz-binding: url(chrome://liberator/content/bindings.xml#compitem-td);
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|||||||
Reference in New Issue
Block a user