1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-23 11:58:00 +01:00

Kill filterURLArray

This commit is contained in:
Kris Maglione
2008-11-29 19:46:29 +00:00
parent 92e8615207
commit 137d9cc939
4 changed files with 65 additions and 75 deletions

View File

@@ -63,7 +63,7 @@ function Bookmarks() //{{{
var bookmarks = []; var bookmarks = [];
var self = this; var self = this;
this.__defineGetter__("name", function () key); this.__defineGetter__("name", function () name);
this.__defineGetter__("store", function () store); this.__defineGetter__("store", function () store);
this.__defineGetter__("bookmarks", function () { this.load(); return bookmarks; }); this.__defineGetter__("bookmarks", function () { this.load(); return bookmarks; });
@@ -324,6 +324,7 @@ function Bookmarks() //{{{
completer: function completer(context, args) completer: function completer(context, args)
{ {
context.quote = null; context.quote = null;
context.filter = args.join(" ");
completion.bookmark(context, args["-tags"]); completion.bookmark(context, args["-tags"]);
}, },
options: [[["-tags", "-T"], commands.OPTION_LIST, null, tags], options: [[["-tags", "-T"], commands.OPTION_LIST, null, tags],
@@ -359,11 +360,9 @@ function Bookmarks() //{{{
// if "bypassCache" is true, it will force a reload of the bookmarks database // if "bypassCache" 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 // on my PC, it takes about 1ms for each bookmark to load, so loading 1000 bookmarks
// takes about 1 sec // takes about 1 sec
get: function get(filter, tags, bypassCache) get: function get(filter, tags, maxItems)
{ {
if (bypassCache) // Is this really necessary anymore? return completion.runCompleter("bookmark", filter, maxItems, tags);
cache.load();
return completion.filterURLArray(cache.bookmarks, filter, tags);
}, },
// if starOnly = true it is saved in the unfiledBookmarksFolder, otherwise in the bookmarksMenuFolder // if starOnly = true it is saved in the unfiledBookmarksFolder, otherwise in the bookmarksMenuFolder

View File

@@ -43,9 +43,7 @@ function CompletionContext(editor, name, offset)
self = this.contexts[name]; self = this.contexts[name];
else else
self.contexts[name] = this; self.contexts[name] = this;
self.filters = parent.filters.slice();
self.incomplete = false; self.incomplete = false;
self.keys = util.cloneObject(parent.keys);
self.message = null; self.message = null;
self.offset = parent.offset + (offset || 0); self.offset = parent.offset + (offset || 0);
self.parent = parent; self.parent = parent;
@@ -53,7 +51,11 @@ function CompletionContext(editor, name, offset)
delete self._filter; // FIXME? delete self._filter; // FIXME?
delete self._generate; delete self._generate;
delete self._ignoreCase; delete self._ignoreCase;
["anchored", "compare", "editor", "filterFunc", "keys", "_process", "quote", "title", "top"].forEach(function (key) ["filters", "keys", "title", "quote"].forEach(function (key) {
if (parent[key])
self[key] = util.cloneObject(parent[key]);
});
["anchored", "compare", "editor", "filterFunc", "keys", "_process", "top"].forEach(function (key)
self[key] = parent[key]); self[key] = parent[key]);
if (self != this) if (self != this)
return self; return self;
@@ -103,7 +105,9 @@ function CompletionContext(editor, name, offset)
this.message = null; this.message = null;
this.name = name || ""; this.name = name || "";
this._completions = []; // FIXME this._completions = []; // FIXME
this.getKey = function (item, key) (typeof self.keys[key] == "function") ? self.keys[key].call(this, item) : item.item[self.keys[key]]; this.getKey = function (item, key) (typeof self.keys[key] == "function") ? self.keys[key].call(this, item) :
key in self.keys ? item.item[self.keys[key]]
: item.item[key];
} }
CompletionContext.prototype = { CompletionContext.prototype = {
// Temporary // Temporary
@@ -162,7 +166,7 @@ CompletionContext.prototype = {
{ {
// Accept a generator // Accept a generator
if (!(items instanceof Array)) if (!(items instanceof Array))
items = [x for (x in items)]; items = [x for (x in Iterator(items))];
delete this.cache.filtered; delete this.cache.filtered;
delete this.cache.filter; delete this.cache.filter;
this.cache.rows = []; this.cache.rows = [];
@@ -1102,67 +1106,6 @@ function Completion() //{{{
completionService.stopSearch(); completionService.stopSearch();
}, },
// discard all entries in the 'urls' array, which don't match 'filter
// urls must be of type [{ url: "..", title: "..", tags: [...], keyword: ".." }, ...]
filterURLArray: function filterURLArray(urls, filter, filterTags)
{
var filtered = [];
// completions which don't match the url but just the description
// list them at the end of the array
var additionalCompletions = [];
if (urls.length == 0)
return [];
var hasTags = urls[0].tags !== undefined;
filterTags = filterTags || [];
// TODO: use ignorecase and smartcase settings
var ignorecase = (filter == filter.toLowerCase() && filterTags.every(function checkMixedCase(t) t == t.toLowerCase()));
if (ignorecase)
{
filter = filter.toLowerCase();
filterTags = filterTags.map(String.toLowerCase);
}
// Longest Common Subsequence
// This shouldn't use buildLongestCommonSubstring for performance
// reasons, so as not to cycle through the urls twice
let filterTokens = filter.split(/\s+/);
for (let [,elem] in Iterator(urls))
{
let item = elem.item || elem; // Kludge
let url = item.url || "";
let title = item.title || "";
let tags = item.tags || [];
if (ignorecase)
{
url = url.toLowerCase();
title = title.toLowerCase();
tags = tags.map(String.toLowerCase);
}
// filter on tags
if (filterTags.some(function aryIndex(tag) tag && tags.indexOf(tag) == -1))
continue;
if (url.indexOf(filter) == -1)
{
// no direct match of filter in the url, but still accept this item
// if _all_ tokens of filter match either the url or the title
if (filterTokens.every(function (token) url.indexOf(token) > -1 || title.indexOf(token) > -1))
additionalCompletions.push(elem);
continue;
}
filtered.push(elem);
}
return filtered.concat(additionalCompletions);
},
// generic helper function which checks if the given "items" array pass "filter" // generic helper function which checks if the given "items" array pass "filter"
// items must be an array of strings // items must be an array of strings
match: function match(items, filter, caseSensitive) match: function match(items, filter, caseSensitive)
@@ -1209,10 +1152,10 @@ function Completion() //{{{
{ {
context.title = ["Bookmark", "Title"]; context.title = ["Bookmark", "Title"];
context.format = bookmarks.format; context.format = bookmarks.format;
context.completions = bookmarks.get(context.filter) // Need to make a copy because set completions() checks instanceof Array,
context.filters = []; // and this may be an Array from another window.
if (tags) context.completions = Array.slice(storage["bookmark-cache"].bookmarks);
context.filters.push(function ({ item: item }) tags.every(function (tag) item.tags.indexOf(tag) > -1)); completion.urls(context, tags);
}, },
buffer: function buffer(context) buffer: function buffer(context)
@@ -1659,6 +1602,49 @@ function Completion() //{{{
this.urlCompleters[opt] = UrlCompleter.apply(null, Array.slice(arguments)); this.urlCompleters[opt] = UrlCompleter.apply(null, Array.slice(arguments));
}, },
urls: function (context, tags)
{
let compare = String.localeCompare;
let contains = String.indexOf
if (context.ignoreCase)
{
compare = util.compareIgnoreCase;
contains = function (a, b) a && a.toLowerCase().indexOf(b.toLowerCase()) > -1;
}
if (tags)
context.filters.push(function (item) tags.
every(function (tag) (context.getKey(item, "tags") || []).
some(function (t) !compare(tag, t))));
if (!context.title)
context.title = ["URL", "Title"];
context.fork("additional", 0, this, function (context) {
context.title[0] += " (additional)";
context.filter = context.parent.filter; // FIXME
context.completions = context.parent.completions;
// For items whose URL doesn't exactly match the filter,
// accept them if all tokens match either the URL or the title.
// Filter out all directly matching strings.
let match = context.filters[0];
context.filters[0] = function (item) !match.call(this, item);
// and all that don't match the tokens.
let tokens = context.filter.split(/\s+/);
context.filters.push(function (item) tokens.every(
function (tok) contains(context.getKey(item, "url"), tok) ||
contains(context.getKey(item, "title"), tok)));
let re = RegExp(tokens.filter(util.identity).map(util.escapeRegex).join("|"), "g");
function highlight(item, text, i) process[i].call(this, item, template.highlightRegexp(text, re));
let process = [template.icon, function (item, k) k];
context.process = [
function (item, text) highlight.call(this, item, item.text, 0),
function (item, text) highlight.call(this, item, text, 1)
];
});
},
userCommand: function userCommand(context) userCommand: function userCommand(context)
{ {
context.title = ["User Command", "Definition"]; context.title = ["User Command", "Definition"];

View File

@@ -169,8 +169,11 @@ const template = {
str = String(str).replace(" ", "\u00a0"); str = String(str).replace(" ", "\u00a0");
let s = <></>; let s = <></>;
let start = 0; let start = 0;
let n = 0;
for (let [i, length] in iter) for (let [i, length] in iter)
{ {
if (n++ > 8)
return s + <>{str.substr(start)}</>;
XML.ignoreWhitespace = false; XML.ignoreWhitespace = false;
s += <>{str.substring(start, i)}</>; s += <>{str.substring(start, i)}</>;
s += highlight(str.substr(i, length)); s += highlight(str.substr(i, length));

View File

@@ -138,6 +138,8 @@ const util = { //{{{
cloneObject: function cloneObject(obj) cloneObject: function cloneObject(obj)
{ {
if (obj instanceof Array)
return obj.slice();
let newObj = {}; let newObj = {};
for (let [k, v] in Iterator(obj)) for (let [k, v] in Iterator(obj))
newObj[k] = v; newObj[k] = v;