diff --git a/content/bookmarks.js b/content/bookmarks.js index f69410d5..f3c9bbe1 100644 --- a/content/bookmarks.js +++ b/content/bookmarks.js @@ -744,33 +744,34 @@ function History() //{{{ return { + get format() bookmarks.format, + get service() historyService, get: function (filter, maxItems) { - let items = []; - // no query parameters will get all history let query = historyService.getNewQuery(); - query.searchTerms = filter; - let options = historyService.getNewQueryOptions(); + + for (let [k, v] in Iterator(filter)) + query[k] = v; options.sortingMode = options.SORT_BY_DATE_DESCENDING; + options.resultType = options.RESULTS_AS_URI; if (maxItems > 0) options.maxResults = maxItems; // execute the query let root = historyService.executeQuery(query, options).root; root.containerOpen = true; - for (let i in util.range(0, root.childCount)) - { + let items = util.map(util.range(0, root.childCount), function (i) { let node = root.getChild(i); - if (node.type == node.RESULT_TYPE_URI) - items.push({ url: node.uri, - title: node.title, - icon: node.icon ? node.icon.spec : DEFAULT_FAVICON - }) - } + return { + url: node.uri, + title: node.title, + icon: node.icon ? node.icon.spec : DEFAULT_FAVICON + } + }); root.containerOpen = false; // close a container after using it! return items; @@ -821,7 +822,7 @@ function History() //{{{ if (openItems) return liberator.open([i[0] for each (i in items)], liberator.NEW_TAB); - let list = template.genericTable(items, bookmarks.format); + let list = template.genericTable(items, this.format); commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE); } }; diff --git a/content/completion.js b/content/completion.js index 5d132c23..c2cfdab1 100644 --- a/content/completion.js +++ b/content/completion.js @@ -69,12 +69,12 @@ function CompletionContext(editor, name, offset) else this.editor = editor; this.filterFunc = completion.filter; - this.title = ["Completions"]; this.keys = { text: 0, description: 1, icon: "icon" }; - this.top = this; this.offset = offset || 0; - this.tabPressed = false; this.onUpdate = function () true; + this.tabPressed = false; + this.title = ["Completions"]; + this.top = this; this.contexts = { name: this }; this.__defineGetter__("incomplete", function () this.contextList.some(function (c) c.parent && c.incomplete)); this.selectionTypes = {}; @@ -118,6 +118,9 @@ CompletionContext.prototype = { get createRow() this._createRow || template.completionRow, // XXX set createRow(createRow) this._createRow = createRow, + get filterFunc() this._filterFunc || function (items) items, + set filterFunc(val) this._filterFunc = val, + get regenerate() this._generate && (!this.completions || this.cache.key != this.key || this.cache.offset != this.offset), set regenerate(val) { if (val) delete this.cache.offset }, @@ -882,7 +885,7 @@ function Completion() //{{{ ////////////////////// PUBLIC SECTION ////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ - return { + let self = { // FIXME get getKey() this._getKey || function (item, key) item[{ text: 0, description: 1, icon: 2 }[key]], @@ -1167,7 +1170,7 @@ function Completion() //{{{ if (compObject != null) { cmdContext.advance(compObject.start); - cmdContext.filterFunc = function (k) k; + cmdContext.filterFunc = null; cmdContext.completions = compObject.items; } } @@ -1232,6 +1235,15 @@ function Completion() //{{{ } }, + history: function (context) + { + context.format = history.format; + context.title = ["History"] + context.background = true; + context.regenerate = true; + context.generate = function () history.get({ searchTerms: context.filter }); + }, + get javascriptCompleter() javascript, javascript: function _javascript(context) @@ -1239,6 +1251,35 @@ function Completion() //{{{ return javascript.complete(context); }, + location: function (context) + { + if (!completionService) + return + context.title = ["Smart Completions"]; + context.keys.icon = 2; + context.incomplete = true; + context.hasItems = context.completions.length > 0; // XXX + context.filterFunc = null; + let timer = new util.Timer(50, 100, function (result) { + context.completions = [ + [result.getValueAt(i), result.getCommentAt(i), result.getImageAt(i)] + for (i in util.range(0, result.matchCount)) + ]; + context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING; + let filter = context.filter; + context.completions.forEach(function ([item]) buildSubstrings(item, filter)); + }); + completionService.stopSearch(); + completionService.startSearch(context.filter, "", context.result, { + onSearchResult: function onSearchResult(search, result) { + context.result = result; + timer.tell(result); + if (result.searchResult <= result.RESULT_SUCCESS) + timer.flush(); + } + }); + }, + macro: function macro(filter) { var macros = [item for (item in events.getMacros())]; @@ -1272,34 +1313,21 @@ function Completion() //{{{ let item = keywords.filter(function (k) k.keyword == keyword)[0]; if (item && item.url.indexOf("%s") > -1) context.fork("keyword/" + keyword, keyword.length + space.length, function (context) { + context.format = history.format; context.title = [keyword + " Quick Search"]; context.background = true; context.anchored = true; + context.quote = decodeURIComponent; context.generate = function () { let [begin, end] = item.url.split("%s"); - let history = modules.history.service; - let query = history.getNewQuery(); - let opts = history.getNewQueryOptions(); - query.uri = window.makeURI(begin); - query.uriIsPrefix = true; - opts.resultType = opts.RESULTS_AS_URI; - opts.queryType = opts.QUERY_TYPE_HISTORY; - - let results = history.executeQuery(query, opts); - let root = results.root; - root.containerOpen = true; - let result = util.map(util.range(0, root.childCount), function (i) { - let child = root.getChild(i); - let rest = child.uri.length - end.length; - let query = child.uri.substring(begin.length, rest); - if (child.uri.substr(rest) == end && query.indexOf("&") == -1) - return [decodeURIComponent(query.replace("+", "%20")), - child.title, - child.icon]; + return history.get({ uri: window.makeURI(begin), uriIsPrefix: true }).map(function (item) { + let rest = item.url.length - end.length; + let query = item.url.substring(begin.length, rest); + item.url = query; + if (item.url.substr(rest) == end && query.indexOf("&") == -1) + return item; }).filter(function (k) k); - root.containerOpen = false; - return result; }; }); }, @@ -1397,43 +1425,16 @@ function Completion() //{{{ if (skip) context.advance(skip[0].length); - let opts = { - s: this.search, - f: this.file, - S: this.searchEngineSuggest, - b: this.bookmark, - l: function l(context) - { - if (!completionService) - return - context.title = ["Smart Completions"]; - context.keys.icon = 2; - context.incomplete = true; - context.hasItems = context.completions.length > 0; // XXX - context.filterFunc = function (items) items; - let timer = new util.Timer(50, 100, function (result) { - context.completions = [ - [result.getValueAt(i), result.getCommentAt(i), result.getImageAt(i)] - for (i in util.range(0, result.matchCount)) - ]; - context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING; - let filter = context.filter; - context.completions.forEach(function ([item]) buildSubstrings(item, filter)); - }); - completionService.stopSearch(); - completionService.startSearch(context.filter, "", context.result, { - onSearchResult: function onSearchResult(search, result) { - context.result = result; - timer.tell(result); - if (result.searchResult <= result.RESULT_SUCCESS) - timer.flush(); - } - }); - } - }; // Will, and should, throw an error if !(c in opts) Array.forEach(complete || options["complete"], - function (c) context.fork(c, 0, opts[c], completion)); + function (c) context.fork(c, 0, completion.urlCompleters[c].completer, completion)); + }, + + urlCompleters: {}, + + addUrlCompleter: function (opt) + { + this.urlCompleters[opt] = UrlCompleter.apply(null, Array.slice(arguments)); }, // FIXME: Temporary @@ -1461,6 +1462,16 @@ function Completion() //{{{ } // }}} }; + + const UrlCompleter = new Struct("name", "description", "completer"); + self.addUrlCompleter("S", "Suggest engines", self.searchEngineSuggest); + self.addUrlCompleter("b", "Bookmarks", self.bookmark); + self.addUrlCompleter("h", "History", self.history); + self.addUrlCompleter("f", "Local files", self.file); + self.addUrlCompleter("l", "Firefox location bar entries (bookmarks and history sorted in an intelligent way)", self.location); + self.addUrlCompleter("s", "Search engines and keyword URLs", self.search); + + return self; //}}} }; //}}} diff --git a/content/ui.js b/content/ui.js index 16bd24c5..e6df59b1 100644 --- a/content/ui.js +++ b/content/ui.js @@ -316,18 +316,8 @@ function CommandLine() //{{{ "Items which are completed at the :[tab]open prompt", "charlist", "sfl", { - completer: function completer(filter) - { - return [ - ["s", "Search engines and keyword URLs"], - ["f", "Local files"], - ["b", "Bookmarks"], - ["h", "History"], - ["l", "Firefox location bar entries (bookmarks and history sorted in an intelligent way)"], - ["S", "Suggest engines"] - ]; - }, - validator: function validator(value) !/[^sfbhSl]/.test(value) + completer: function completer(filter) [k for each (k in completion.urlCompleters)], + validator: function validator(value) value in completion.urlCompleters }); options.add(["history", "hi"],