From 129f7f23f714ee865671a95359d1267ffe56f0b6 Mon Sep 17 00:00:00 2001 From: Martin Stubenschrott Date: Thu, 18 Oct 2007 16:45:22 +0000 Subject: [PATCH] :bmarks [filter] works again, now even with -tags=foo filtering --- content/bookmarks.js | 43 +++++----- content/commands.js | 30 ++++--- content/completion.js | 180 ++++++++++++++++++++++++------------------ content/util.js | 10 ++- skin/vimperator.css | 2 +- 5 files changed, 149 insertions(+), 116 deletions(-) diff --git a/content/bookmarks.js b/content/bookmarks.js index ad519901..94a61278 100644 --- a/content/bookmarks.js +++ b/content/bookmarks.js @@ -99,17 +99,15 @@ function Bookmarks() //{{{ ////////////////////// PUBLIC SECTION ////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ - // FIXME: add filtering here rather than having to calling get_bookmark_completions() - // // if "bypass_cache" is true, it will force a reload of the bookmarks database // on my PC, it takes about 1ms for each bookmark to load, so loading 1000 bookmarks // takes about 1 sec - this.get = function(filter, bypass_cache) + this.get = function(filter, tags, bypass_cache) { if (!bookmarks || bypass_cache) load(); - return bookmarks; + return vimperator.completion.filterURLArray(bookmarks, filter, tags); } this.add = function (title, url, keyword, tags) @@ -178,6 +176,7 @@ function Bookmarks() //{{{ return count.value; } + // TODO: add filtering // also ensures that each search engine has a Vimperator-friendly alias this.getSearchEngines = function() { @@ -210,6 +209,7 @@ function Bookmarks() //{{{ return search_engines; } + // TODO: add filtering // format of returned array: // [keyword, helptext, url] this.getKeywords = function() @@ -271,7 +271,7 @@ function Bookmarks() //{{{ return url; // can be null } - this.list = function(filter, fullmode) + this.list = function(filter, tags, fullmode) { if (fullmode) { @@ -279,8 +279,7 @@ function Bookmarks() //{{{ } else { - //var items = vimperator.completion.get_bookmark_completions(filter); - var items = this.get(filter, false); + var items = this.get(filter, tags, false); if (items.length == 0) { @@ -375,14 +374,12 @@ function History() //{{{ ////////////////////// PUBLIC SECTION ////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ - // FIXME: add filtering here rather than having to call - // get_bookmark_completions() - this.get = function() + this.get = function(filter) { if (!history) load(); - return history; + return vimperator.completion.filterURLArray(history, filter); } // the history is automatically added to the Places global history @@ -451,7 +448,7 @@ function History() //{{{ } else { - var items = vimperator.completion.get_history_completions(filter); + var items = this.get(filter); if (items.length == 0) { @@ -463,22 +460,18 @@ function History() //{{{ return; } + var list = ":" + vimperator.util.escapeHTML(vimperator.commandline.getCommand()) + "
" + + ""; for (var i = 0; i < items.length; i++) { - var list = ":" + vimperator.util.escapeHTML(vimperator.commandline.getCommand()) + "
" + - "
titleURL
"; - for (var i = 0; i < items.length; i++) - { - var title = vimperator.util.escapeHTML(items[i][1]); - if (title.length > 50) - title = title.substr(0, 47) + "..."; - var url = vimperator.util.escapeHTML(items[i][0]); - list += ""; - } - list += "
titleURL
" + title + "" + url + "
"; - - vimperator.commandline.echo(list, vimperator.commandline.HL_NORMAL, vimperator.commandline.FORCE_MULTILINE); + var title = vimperator.util.escapeHTML(items[i][1]); + if (title.length > 50) + title = title.substr(0, 47) + "..."; + var url = vimperator.util.escapeHTML(items[i][0]); + list += "" + title + "" + url + ""; } + list += ""; + vimperator.commandline.echo(list, vimperator.commandline.HL_NORMAL, vimperator.commandline.FORCE_MULTILINE); } } //}}} diff --git a/content/commands.js b/content/commands.js index bec5e067..7780f947 100644 --- a/content/commands.js +++ b/content/commands.js @@ -516,7 +516,7 @@ function Commands() //{{{ var entry = sh.getEntryAtIndex(i, false); var url = entry.URI.spec; var title = entry.title; - if (vimperator.completion.match(filter, [url, title], false)) + if (vimperator.completion.match([url, title], filter, false)) completions.push([url, title]); } return completions; @@ -575,15 +575,27 @@ function Commands() //{{{ } )); addDefaultCommand(new Command(["bmarks"], - function(args, special) { vimperator.bookmarks.list(args, special); }, + function(args, special) + { + var res = parseArgs(args, this.args); + if (res.error) + { + vimperator.echoerr(res.error); + return false; + } + + var tags = getOption(res.opts, "-tags", []); + vimperator.bookmarks.list(res.args.join(" "), tags, special); + }, { usage: ["bmarks [filter]", "bmarks!"], short_help: "Show bookmarks", help: "Open the message window at the bottom of the screen with all bookmarks which match [filter] either in the title or URL.
" + "The special version :bmarks! will open the default Firefox bookmarks window.
" + - "The following options WILL be interpreted in the future:
" + - " -T comma,separated,tag,list
", - completer: function(filter) { return vimperator.completion.get_bookmark_completions(filter); } + "Filter can also contain the following options:
" + + "-tags=comma,separated,tag,list
", + completer: function(filter) { return vimperator.bookmarks.get(filter); }, + args: [[["-tags", "-T"], OPTION_LIST]] } )); addDefaultCommand(new Command(["b[uffer]"], @@ -637,7 +649,7 @@ function Commands() //{{{ "The following options WILL be interpreted in the future:
" + " [!] a special version to delete ALL bookmarks
" + " -T comma,separated,tag,list
", - completer: function(filter) { return vimperator.completion.get_bookmark_completions(filter); } + completer: function(filter) { return vimperator.bookmarks.get(filter); } } )); addDefaultCommand(new Command(["com[mand]"], @@ -858,7 +870,7 @@ function Commands() //{{{ var entry = sh.getEntryAtIndex(i, false); var url = entry.URI.spec; var title = entry.title; - if (vimperator.completion.match(filter, [url, title], false)) + if (vimperator.completion.match([url, title], filter, false)) completions.push([url, title]); } return completions; @@ -895,7 +907,7 @@ function Commands() //{{{ short_help: "Show recently visited URLs", help: "Open the message window at the bottom of the screen with all history items which match [filter] either in the title or URL.
" + "The special version :history! will open the default Firefox history window.", - completer: function(filter) { return vimperator.completion.get_history_completions(filter); } + completer: function(filter) { return vimperator.history.get(filter); } } )); addDefaultCommand(new Command(["javas[cript]", "js"], @@ -1853,7 +1865,7 @@ function Commands() //{{{ // undoItems[i].image is also available if need for favicons var url = undoItems[i].state.entries[0].url; var title = undoItems[i].title; - if (vimperator.completion.match(filter, [url, title], false)) + if (vimperator.completion.match([url, title], filter, false)) completions.push([url, title]); } return completions; diff --git a/content/completion.js b/content/completion.js index 7971e328..23e66e5f 100644 --- a/content/completion.js +++ b/content/completion.js @@ -104,65 +104,6 @@ vimperator.completion = (function() // {{{ return filtered; } //}}} - /* discard all entries in the 'urls' array, which don't match 'filter */ - function filter_url_array(urls, filter) //{{{ - { - var filtered = []; - // completions which don't match the url but just the description - // list them add the end of the array - var additional_completions = []; - - if (!filter) return urls.map(function($_) { - return [$_[0], $_[1]] - }); - - var ignorecase = false; - if (filter == filter.toLowerCase()) - ignorecase = true; - - /* - * Longest Common Subsequence - * This shouldn't use build_longest_common_substring - * for performance reasons, so as not to cycle through the urls twice - */ - for (var i = 0; i < urls.length; i++) - { - var url = urls[i][0] || ""; - var title = urls[i][1] || ""; - if (ignorecase) - { - url = url.toLowerCase(); - title = title.toLowerCase(); - } - - if (url.indexOf(filter) == -1) - { - if (title.indexOf(filter) != -1) - additional_completions.push([ urls[i][0], urls[i][1] ]); - continue; - } - if (g_substrings.length == 0) // Build the substrings - { - var last_index = url.lastIndexOf(filter); - var url_length = url.length; - for (var k = url.indexOf(filter); k != -1 && k <= last_index; k = url.indexOf(filter, k + 1)) - { - for (var l = k + filter.length; l <= url_length; l++) - g_substrings.push(url.substring(k, l)); - } - } - else - { - g_substrings = g_substrings.filter(function($_) { - return url.indexOf($_) >= 0; - }); - } - filtered.push([urls[i][0], urls[i][1]]); - } - - return filtered.concat(additional_completions); - } //}}} - return { /* * returns the longest common substring @@ -201,9 +142,9 @@ vimperator.completion = (function() // {{{ if (cpt[i] == 's') completions = completions.concat(this.get_search_completions(filter)); else if (cpt[i] == 'b') - completions = completions.concat(this.get_bookmark_completions(filter)); + completions = completions.concat(vimperator.bookmarks.get(filter)); else if (cpt[i] == 'h') - completions = completions.concat(this.get_history_completions(filter)); + completions = completions.concat(vimperator.history.get(filter)); else if (cpt[i] == 'f') completions = completions.concat(this.get_file_completions(filter, true)); } @@ -224,18 +165,6 @@ vimperator.completion = (function() // {{{ return build_longest_common_substring(mapped, filter); }, //}}} - get_history_completions: function(filter) //{{{ - { - var items = vimperator.history.get(); - return filter_url_array(items, filter); - }, //}}} - - get_bookmark_completions: function(filter) //{{{ - { - var bookmarks = vimperator.bookmarks.get(); - return filter_url_array(bookmarks, filter); - }, //}}} - // TODO: support file:// and \ or / path separators on both platforms get_file_completions: function(filter) //{{{ { @@ -540,10 +469,104 @@ vimperator.completion = (function() // {{{ return build_longest_starting_substring(completions, filter); }, // }}} - // helper function which checks if the given arguments pass "filter" + // discard all entries in the 'urls' array, which don't match 'filter + // urls must be of type [["url", "title"], [...]] or optionally + // [["url", "title", keyword, [tags]], [...]] + filterURLArray: function(urls, filter, tags) //{{{ + { + var filtered = []; + // completions which don't match the url but just the description + // list them add the end of the array + var additional_completions = []; + + if (urls.length == 0) + return []; + + var hasTags = urls[0].length >= 4; + // TODO: create a copy of urls? + if (!filter && (!hasTags || !tags)) + return urls; + + tags = tags || []; + + // TODO: use ignorecase and smartcase settings + var ignorecase = true; + if (filter != filter.toLowerCase() || tags.join(",") != tags.join(",").toLowerCase()) + ignorecase = false; + + if (ignorecase) + { + filter = filter.toLowerCase(); + tags = tags.map(function(t) { return t.toLowerCase(); }); + } + + /* + * Longest Common Subsequence + * This shouldn't use build_longest_common_substring + * for performance reasons, so as not to cycle through the urls twice + */ + outer: + for (var i = 0; i < urls.length; i++) + { + var url = urls[i][0] || ""; + var title = urls[i][1] || ""; + var tag = urls[i][3] || []; + + if (ignorecase) + { + url = url.toLowerCase(); + title = title.toLowerCase(); + tag = tag.map(function(t) { return t.toLowerCase(); }); + } + + // filter on tags + for (var j = 0; j < tags.length; j++) + { + if (!tags[j]) + continue; + + if (tag.indexOf(tags[j]) == -1) + continue outer; + } + + if (url.indexOf(filter) == -1) + { + if (title.indexOf(filter) >= 0) + additional_completions.push(urls[i]); + + continue; + } + + // TODO: refactor out? And just build if wildmode contains longest? + if (g_substrings.length == 0) // Build the substrings + { + var last_index = url.lastIndexOf(filter); + var url_length = url.length; + if (last_index >= 0 && last_index < url_length) // do not build substrings, if we don't match filter + { + for (var k = url.indexOf(filter); k != -1 && k <= last_index; k = url.indexOf(filter, k + 1)) + { + for (var l = k + filter.length; l <= url_length; l++) + g_substrings.push(url.substring(k, l)); + } + } + } + else + { + g_substrings = g_substrings.filter(function($_) { + return url.indexOf($_) >= 0; + }); + } + + filtered.push(urls[i]); + } + + return filtered.concat(additional_completions); + }, //}}} + + // generic helper function which checks if the given "items" array pass "filter" // items must be an array of strings - // if case_sensitive == true, be sure to pass filter already in lowercased version - match: function(filter, items, case_sensitive) + match: function(items, filter, case_sensitive) { if (typeof(filter) != "string" || !items) return false; @@ -552,15 +575,16 @@ vimperator.completion = (function() // {{{ { for (var i = 0; i < items.length; i++) { - if (items[i].toLowerCase().indexOf(filter) > -1) + if (items[i].indexOf(filter) > -1) return true; } } else { + filter = filter.toLowerCase(); for (var i = 0; i < items.length; i++) { - if (items[i].indexOf(filter) > -1) + if (items[i].toLowerCase().indexOf(filter) > -1) return true; } } diff --git a/content/util.js b/content/util.js index 6269a758..0d8c7d6f 100644 --- a/content/util.js +++ b/content/util.js @@ -29,9 +29,13 @@ the terms of any one of the MPL, the GPL or the LGPL. vimperator.util = { escapeHTML: function(str) { - var e = window.content.document.createElement("div"); - e.appendChild(window.content.document.createTextNode(str)); - return e.innerHTML; + // XXX: the following code is _much- slower then a simple .replace() + // :history display went down from 2 to 1 second after changing + // + // var e = window.content.document.createElement("div"); + // e.appendChild(window.content.document.createTextNode(str)); + // return e.innerHTML; + return str.replace(//, ">"); }, // TODO: use :highlight color groups diff --git a/skin/vimperator.css b/skin/vimperator.css index 4e32e9b4..ef415e5b 100644 --- a/skin/vimperator.css +++ b/skin/vimperator.css @@ -151,7 +151,7 @@ the terms of any one of the MPL, the GPL or the LGPL. text-decoration: none; } a.hl-URL:hover { - background-color: gray; + text-decoration: underline; } /* MOW */