From ef0b517d3f434546722d6a4ec7ce41d71a224661 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Sat, 22 Nov 2008 09:14:21 +0000 Subject: [PATCH] More completion stuff --- content/completion.js | 35 +++++++---- content/style.js | 1 + content/template.js | 32 ++++++++++ content/ui.js | 137 +++++++++++++++--------------------------- skin/liberator.css | 4 +- 5 files changed, 108 insertions(+), 101 deletions(-) diff --git a/content/completion.js b/content/completion.js index b6ab7e96..6933ec3d 100644 --- a/content/completion.js +++ b/content/completion.js @@ -43,13 +43,18 @@ function CompletionContext(editor, name, offset) name = parent.name + "/" + name; this.contexts = parent.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.parent = parent; this.editor = parent.editor; this.offset = parent.offset + (offset || 0); this.__defineGetter__("tabPressed", function () this.parent.tabPressed); this.__defineGetter__("onUpdate", function () this.parent.onUpdate); + this.__defineGetter__("value", function () this.parent.value); this.incomplete = false; } else @@ -94,6 +99,9 @@ CompletionContext.prototype = { 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 items() this._items, @@ -104,7 +112,8 @@ CompletionContext.prototype = { 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) { @@ -154,6 +163,7 @@ CompletionContext.prototype = { this.selectionTypes = {}; this.tabPressed = false; 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))) // delete this.contexts[key]; 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. key = util.escapeString(key.substr(offset), ""); - completion.filterString = key; let res = buildLongestStartingSubstring(compl, key); if (res.length == 0) { @@ -529,7 +538,7 @@ function Completion() //{{{ cacheKey = str.substring(statement, dot); obj = self.eval(s, cacheKey, obj); } - return [[obj], str.substring(statement, stop + 1)]; + return [[obj, str.substring(statement, stop + 1)]]; } function getObjKey(frame) @@ -692,7 +701,6 @@ function Completion() //{{{ // list = [ [['com1', 'com2'], 'text'], [['com3', 'com4'], 'text'] ] function buildLongestCommonSubstring(list, filter, favicon) { - completion.filterString = filter; var filtered = []; var ignorecase = false; @@ -1027,13 +1035,13 @@ function Completion() //{{{ 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"); - lines.splice(lines.length - 1, 1); + lines.pop(); let vars = lines.map(function (line) { - let matches = line.match(/([^=]+)=(.+)/); + let matches = line.match(/([^=]+)=(.+)/) || []; return [matches[1], matches[2]]; }); @@ -1044,7 +1052,6 @@ function Completion() //{{{ ex: function ex(context) { this.filterMap = null; - this.filterString = ""; substrings = []; if (context.filter.indexOf(cacheFilter["ex"]) != 0) { @@ -1069,7 +1076,6 @@ function Completion() //{{{ { [prefix] = context.filter.match(/^(?:\w*[\s!]|!)\s*/); context = context.fork(cmd, prefix.length); - this.filterString = context.filter; args = command.parseArgs(context.filter, true); if (args) { @@ -1220,7 +1226,6 @@ function Completion() //{{{ // XXX: Move to bookmarks.js? searchEngineSuggest: function (context, engineAliases) { - this.filterString = context.filter; if (!filter) return [0, []]; @@ -1325,7 +1330,6 @@ function Completion() //{{{ // if the 'complete' argument is passed like "h", it temporarily overrides the complete option url: function url(context, complete) { - this.filterString = context.filter; var numLocationCompletions = 0; // how many async completions did we already return to the caller? var start = 0; var skip = context.filter.match("^.*" + options["urlseparator"]); // start after the last 'urlseparator' @@ -1339,6 +1343,13 @@ function Completion() //{{{ b: function (context) { 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) }, l: function (context) diff --git a/content/style.js b/content/style.js index aabb000b..d8af138a 100644 --- a/content/style.js +++ b/content/style.js @@ -28,6 +28,7 @@ function Highlights(name, store, serial) NonText color: blue; min-height: 16px; padding-left: 2px; + CompTitle color: magenta; background: white; font-weight: bold; CompItem CompItem[selected] background: yellow; CompItem>* padding: 0 .5ex; diff --git a/content/template.js b/content/template.js index 2860f1bc..66e745ea 100644 --- a/content/template.js +++ b/content/template.js @@ -32,6 +32,38 @@ const template = { 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 ; + }, + // if "processStrings" is true, any passed strings will be surrounded by " and // any line breaks are displayed as \n highlight: function (arg, processStrings) diff --git a/content/ui.js b/content/ui.js index 915bde6d..2be9b50c 100644 --- a/content/ui.js +++ b/content/ui.js @@ -842,7 +842,7 @@ function CommandLine() //{{{ //if (options.get("wildoptions").has("sort")) // completions.items.sort(function (a, b) String.localeCompare(a[0], b[0])); - completionList.setItems(completionContext.allItems); + completionList.setItems(completionContext); } if (completions.items.length == 0) @@ -1243,7 +1243,7 @@ function CommandLine() //{{{ //if (newCompletions.incompleteResult && newCompletions.items.length == 0) // return; - completionList.setItems(newCompletions.items); + completionList.setItems(completionContext); // try to keep the old item selected 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.appendChild(doc.createTextNode("")); - var items = []; + var items = null; var startIndex = -1; // The index of the first displayed item var endIndex = -1; // The index one *after* the last displayed item var selIndex = -1; // The index of the currently selected element @@ -1333,40 +1333,6 @@ function ItemList(id) //{{{ 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 = - ; - - if (dom) - return util.xmlToDom(row, doc); - return row; - } - function getCompletion(index) completionElements[index - startIndex]; /** @@ -1378,60 +1344,56 @@ function ItemList(id) //{{{ function fill(offset) { 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; 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; - - if (diff == 1) /* Scroll down */ - { - 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); - } + let len = context.items.length; + let start = off; + off += len; + return util.range(Math.max(offset - start, 0), Math.min(endIndex - start, len)); } - else - { - // do a full refill of the list: - XML.ignoreWhitespace = true; - let xml =
- Completions: -
- { - template.map(util.range(offset, endIndex), function (i) - "xml" in items[i] ? items[i].xml : createDefaultRow(items[i])) - } -
-
- { - // 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) -
  • ~
) - } -
-
; - div = util.xmlToDom(xml, doc); - completionBody = div.getElementsByClassName("hl-Completions")[0]; - //completionElements = completionBody.childNodes; // Kris: This is broken for things like :dia pr - completionElements = div.getElementsByClassName("hl-CompItem"); - doc.body.replaceChild(div, doc.body.firstChild); - autoSize(); - } + let xml =
+ { + items.allItems.items.length == 0 && +
+ No Completions +
|| <> + } + { + template.map(items.contextList, function (context) context.hasItems && +
+ { context.createRow(context, context.title || {}, "hl-CompTitle") } + { + template.map(range(context), function (i) context.createRow(context, context.items[i])) + } +
+ || undefined) + } +
+ { + // 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) +
  • ~
) + } +
+
; + + div = util.xmlToDom(xml, doc); + completionBody = div.getElementsByClassName("hl-Completions")[0]; + //completionElements = completionBody.childNodes; // Kris: This is broken for things like :dia pr + 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) { startIndex = endIndex = selIndex = -1; - items = newItems || []; + items = newItems; if (typeof selectedItem == "number") { this.selectItem(selectedItem); @@ -1474,7 +1436,8 @@ function ItemList(id) //{{{ //if (container.collapsed) // fixme // 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) getCompletion(selIndex).removeAttribute("selected"); @@ -1491,7 +1454,7 @@ function ItemList(id) //{{{ else if (index <= startIndex + CONTEXT_LINES) newOffset = index - CONTEXT_LINES; - newOffset = Math.min(newOffset, items.length - maxItems); + newOffset = Math.min(newOffset, len - maxItems); newOffset = Math.max(newOffset, 0); if (selIndex > -1) diff --git a/skin/liberator.css b/skin/liberator.css index f6bc9916..a7c6354c 100644 --- a/skin/liberator.css +++ b/skin/liberator.css @@ -60,13 +60,13 @@ the terms of any one of the MPL, the GPL or the LGPL. width: 100%; display: table; } -.hl-CompItem { +.hl-CompItem, .hl-CompTitle { display: table-row; } .hl-Completions > ul { display: table-row; } -.hl-CompItem > * { +.hl-CompItem > *, .hl-CompTitle > * { -moz-binding: url(chrome://liberator/content/bindings.xml#compitem-td); display: table-cell; vertical-align: middle;