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

More completion stuff. And move vimperator.png to chrome://liberator2/content/ -- long story.

This commit is contained in:
Kris Maglione
2008-11-24 10:10:49 +00:00
parent b2a87273f8
commit 9b14f6e331
14 changed files with 376 additions and 330 deletions

View File

@@ -22,7 +22,7 @@ JAR_TXT_FILES = ${shell find -L content skin locale \
\) \ \) \
} }
JAR_DIRS = $(foreach f,${JAR_FILES},$(dir $f)) JAR_DIRS = $(foreach f,${JAR_FILES},$(dir $f))
JAR_BIN_FILES = ${shell find content skin \ JAR_BIN_FILES = ${shell find content skin webcontent \
-type f \ -type f \
-a ! -path '*CVS*' \ -a ! -path '*CVS*' \
-a -path '*.png' \ -a -path '*.png' \

View File

@@ -1,4 +1,5 @@
# Firefox # Firefox
content liberator2 webcontent/ contentaccessible=yes
content liberator content/ content liberator content/
resource liberator modules/ resource liberator modules/
locale liberator en-US locale/en-US/ locale liberator en-US locale/en-US/

View File

@@ -349,6 +349,11 @@ function Bookmarks() //{{{
return { return {
get format() ({
keys: ["url", "title"],
process: [template.icon, template.bookmarkDescription]
}),
// 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
@@ -356,7 +361,7 @@ function Bookmarks() //{{{
{ {
if (bypassCache) // Is this really necessary anymore? if (bypassCache) // Is this really necessary anymore?
cache.load(); cache.load();
return completion.cached("bookmarks", filter, function () cache.bookmarks, "filterURLArray", tags); 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
@@ -490,12 +495,36 @@ function Bookmarks() //{{{
if (engine.alias != newAlias) if (engine.alias != newAlias)
engine.alias = newAlias; engine.alias = newAlias;
searchEngines.push([engine.alias, engine.description, engine.iconURI.spec]); searchEngines.push({ 0: engine.alias, 1: engine.description, icon: engine.iconURI.spec });
} }
return searchEngines; return searchEngines;
}, },
getSuggestions: function (engine, query)
{
let ss = Components.classes["@mozilla.org/browser/search-service;1"]
.getService(Components.interfaces.nsIBrowserSearchService);
const responseType = "application/x-suggestions+json";
let engine = ss.getEngineByAlias(engine);
if (engine && engine.supportsResponseType(responseType))
var queryURI = engine.getSubmission(query, responseType).uri.spec;
if (!queryURI)
return [];
let resp = util.httpGet(queryURI);
let json = Components.classes["@mozilla.org/dom/json;1"]
.createInstance(Components.interfaces.nsIJSON);
try
{
let results = json.decode(resp.responseText)[1];
return [[item, ""] for ([k, item] in Iterator(results)) if (typeof item == "string")];
}
catch (e) {}
return [];
},
// TODO: add filtering // TODO: add filtering
// format of returned array: // format of returned array:
// [keyword, helptext, url] // [keyword, helptext, url]
@@ -512,7 +541,7 @@ function Bookmarks() //{{{
{ {
var url = null; var url = null;
var aPostDataRef = {}; var aPostDataRef = {};
var searchString = (useDefsearch? options["defsearch"] + " " : "") + text; var searchString = (useDefsearch ? options["defsearch"] + " " : "") + text;
// we need to make sure our custom alias have been set, even if the user // we need to make sure our custom alias have been set, even if the user
// did not :open <tab> once before // did not :open <tab> once before
@@ -663,7 +692,7 @@ function History() //{{{
if (args) if (args)
{ {
var sh = getWebNavigation().sessionHistory; var sh = getWebNavigation().sessionHistory;
for (let i = sh.index + 1; i < sh.count; i++) for (let i in util.range(sh.index + 1, sh.count))
{ {
if (sh.getEntryAtIndex(i, false).URI.spec == args) if (sh.getEntryAtIndex(i, false).URI.spec == args)
{ {
@@ -686,7 +715,7 @@ function History() //{{{
let filter = context.filter; let filter = context.filter;
var sh = getWebNavigation().sessionHistory; var sh = getWebNavigation().sessionHistory;
var completions = []; var completions = [];
for (let i = sh.index + 1; i < sh.count; i++) for (let i in util.range(sh.index + 1, sh.count))
{ {
var entry = sh.getEntryAtIndex(i, false); var entry = sh.getEntryAtIndex(i, false);
var url = entry.URI.spec; var url = entry.URI.spec;

View File

@@ -421,12 +421,12 @@ function Commands() //{{{
if (!options) if (!options)
options = []; options = [];
if (!argCount)
argCount = "*";
if (literal) if (literal)
var literalIndex = argCount == "+" ? 0 : Math.max(argCount - 1, 0); var literalIndex = argCount == "+" ? 0 : Math.max(argCount - 1, 0);
if (!argCount)
argCount = "*";
var args = {}; // parsed options var args = {}; // parsed options
args.arguments = []; // remaining arguments args.arguments = []; // remaining arguments
args.string = str; // for access to the unparsed string args.string = str; // for access to the unparsed string
@@ -510,7 +510,7 @@ function Commands() //{{{
count++; // to compensate the "=" character count++; // to compensate the "=" character
} }
else if (sep != null) // this isn't really an option as it has trailing characters, parse it as an argument else if (!/\s/.test(sep)) // this isn't really an option as it has trailing characters, parse it as an argument
{ {
invalid = true; invalid = true;
} }
@@ -623,12 +623,12 @@ function Commands() //{{{
else else
compl = opt[3] || []; compl = opt[3] || [];
context.title = [opt[0][0]]; context.title = [opt[0][0]];
context.items = completion.filter(compl.map(function ([k, v]) [args.quote(k), v]), args.completeFilter);; context.completions = completion.filter(compl.map(function ([k, v]) [args.quote(k), v]), args.completeFilter);;
} }
complete.advance(args.completeStart); complete.advance(args.completeStart);
complete.title = ["Options"]; complete.title = ["Options"];
if (completeOpts) if (completeOpts)
complete.items = completeOpts; complete.completions = completeOpts;
} }
// check for correct number of arguments // check for correct number of arguments

View File

@@ -39,26 +39,26 @@ function CompletionContext(editor, name, offset)
if (editor instanceof arguments.callee) if (editor instanceof arguments.callee)
{ {
let self = this;
let parent = editor; let parent = editor;
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)
{ {
let self = this.contexts[name]; self = this.contexts[name];
self.offset = parent.offset + (offset || 0); self.offset = parent.offset + (offset || 0);
return self; return self;
} }
this.contexts[name] = this; this.contexts[name] = this;
this.top = parent.top; this.anchored = parent.anchored;
this.parent = parent; this.parent = parent;
this.editor = parent.editor;
this.offset = parent.offset + (offset || 0); this.offset = parent.offset + (offset || 0);
this.__defineGetter__("contextList", function () this.top.contextList); ["editor", "filterFunc", "keys", "title", "top"].forEach(function (key)
this.__defineGetter__("onUpdate", function () this.top.onUpdate); self[key] = parent[key]);
this.__defineGetter__("selectionTypes", function () this.top.selectionTypes); ["contextList", "onUpdate", "selectionTypes", "tabPressed", "updateAsync", "value"].forEach(function (key) {
this.__defineGetter__("tabPressed", function () this.top.tabPressed); self.__defineGetter__(key, function () this.top[key]);
this.__defineGetter__("updateAsync", function () this.top.updateAsync); self.__defineSetter__(key, function (val) this.top[key] = val);
this.__defineGetter__("value", function () this.top.value); });
this.incomplete = false; this.incomplete = false;
} }
else else
@@ -67,6 +67,9 @@ function CompletionContext(editor, name, offset)
this._value = editor; this._value = editor;
else else
this.editor = editor; this.editor = editor;
this.filterFunc = completion.filter;
this.title = ["Completions"];
this.keys = [0, 1];
this.top = this; this.top = this;
this.offset = offset || 0; this.offset = offset || 0;
this.tabPressed = false; this.tabPressed = false;
@@ -78,56 +81,139 @@ function CompletionContext(editor, name, offset)
} }
this.name = name || ""; this.name = name || "";
this.cache = {}; this.cache = {};
this._items = []; // FIXME this.process = [];
this._completions = []; // FIXME
} }
CompletionContext.prototype = { CompletionContext.prototype = {
// Temporary // Temporary
get allItems() get allItems()
{ {
let self = this;
let minStart = Math.min.apply(Math, [context.offset for ([k, context] in Iterator(this.contexts)) if (context.items.length && context.hasItems)]); let minStart = Math.min.apply(Math, [context.offset for ([k, context] in Iterator(this.contexts)) if (context.items.length && context.hasItems)]);
let items = []; let items = this.contextList.map(function (context) {
for each (let [k, context] in Iterator(this.contexts)) let prefix = self.value.substring(minStart, context.offset);
{ if (!context.hasItems)
let prefix = this.value.substring(minStart, context.offset); return [];
if (context.hasItems) return context.items;
{ });
items.push(context.items.map(function (item) {
if (!("text" in item))
item = { icon: item[2], text: item[0], description: item[1] };
else // FIXME
item = util.Array.assocToObj([x for (x in Iterator(item))]);
item.text = prefix + item.text;
return item;
}));
}
}
return { start: minStart, items: util.Array.flatten(items) } return { start: minStart, items: util.Array.flatten(items) }
}, },
get caret() (this.editor ? this.editor.selection.getRangeAt(0).startOffset : this.value.length) - this.offset, get caret() (this.editor ? this.editor.selection.getRangeAt(0).startOffset : this.value.length) - this.offset,
get completions() this._completions || [],
set completions(items)
{
delete this.cache.filtered;
delete this.cache.filter;
this.hasItems = items.length > 0;
this._completions = items;
let self = this;
if (this.updateAsync)
liberator.callInMainThread(function () { self.onUpdate.call(self) });
},
get createRow() this._createRow || template.completionRow, // XXX get createRow() this._createRow || template.completionRow, // XXX
set createRow(createRow) this._createRow = createRow, set createRow(createRow) this._createRow = createRow,
get filter() this.value.substr(this.offset, this.caret), 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 },
get items() this._items, get generate() !this._generate ? null : function ()
set items(items)
{ {
this.hasItems = items.length > 0; this._completions = this._generate.call(this);
this._items = items; this.cache.offset = this.offset;
if (this.updateAsync) this.cache.key = this.key;
liberator.callInMainThread(function () { this.onUpdate.call(this) }); return this._completions;
},
set generate(arg)
{
let self = this;
this.hasItems = true;
this._generate = arg;
if (this.background && this.regenerate)
{
let lock = {};
this.cache.backgroundLock = lock;
this.incomplete = true;
liberator.callFunctionInThread(null, function () {
let items = self.generate();
if (self.backgroundLock != lock)
return;
self.incomplete = false;
self.completions = items;
});
}
}, },
get title() this._title || ["Completions"], // XXX get filter() this._filter || this.value.substr(this.offset, this.caret),
set title(val) this._title = val, set filter(val) this._filter = val,
get format() ({
keys: this.keys,
process: this.process
}),
set format(format)
{
this.keys = format.keys;
this.process = format.process;
},
get items()
{
if (!this.hasItems)
return [];
if (this.cache.filtered && this.cache.filter == this.filter)
return this.cache.filtered;
let items = this.completions;
if (this.regenerate)
items = this.generate();
this.cache.filter = this.filter;
if (items == null)
return items;
let self = this;
let text = function (item) item[self.keys[0]];
if (self.quote)
text = function (item) self.quote(item[self.keys[0]]);
this.cache.filtered = this.filterFunc(items.map(function (item) ({ text: text(item), item: item })),
this.filter, this.anchored);
return this.cache.filtered;
},
get process() // FIXME
{
let process = this._process;
process = [process[0] || template.icon, process[1] || function (item, k) k];
let first = process[0];
let filter = this.filter;
if (!this.anchored)
process[0] = function (item, text) first(item, template.highlightFilter(item.text, filter));
return process;
},
set process(process)
{
this._process = process;
},
advance: function advance(count) advance: function advance(count)
{ {
this.offset += count; this.offset += count;
}, },
getItems: function (start, end)
{
let self = this;
let items = this.items;
if (!items)
return [];
let reverse = start > end;
start = Math.max(0, start || 0);
end = Math.min(items.length, end ? end : items.length);
return util.map(util.range(start, end, reverse), function (i) items[i]);
},
fork: function fork(name, offset, completer, self) fork: function fork(name, offset, completer, self)
{ {
let context = new CompletionContext(this, name, offset); let context = new CompletionContext(this, name, offset);
@@ -273,8 +359,6 @@ function Completion() //{{{
if (!(objects instanceof Array)) if (!(objects instanceof Array))
objects = [objects]; objects = [objects];
completion.filterMap = [null, function highlight(v) template.highlight(v, true)];
let [obj, key] = objects; let [obj, key] = objects;
let cache = this.context.cache.objects || {}; let cache = this.context.cache.objects || {};
this.context.cache.objects = cache; this.context.cache.objects = cache;
@@ -307,30 +391,27 @@ function Completion() //{{{
return cache[key] = compl; return cache[key] = compl;
} }
this.filter = function filter(compl, key, last, offset) this.filter = function filter(context, compl, name, anchored, key, last, offset)
{ {
context.title = [name];
context.anchored = anchored;
context.filter = key;
context.process = [null, function highlight(item, v) template.highlight(v, true)];
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), "");
let res = buildLongestStartingSubstring(compl, key);
if (res.length == 0)
{
substrings = [];
res = buildLongestCommonSubstring(compl, key);
}
if (last != undefined) // Prepend the quote delimiter to the substrings list, so it's not stripped on <Tab> if (last != undefined) // Prepend the quote delimiter to the substrings list, so it's not stripped on <Tab>
substrings = substrings.map(function (s) last + s); substrings = substrings.map(function (s) last + s);
let res;
if (last != undefined) // We're looking for a quoted string, so, strip whatever prefix we have and quote the rest if (last != undefined) // We're looking for a quoted string, so, strip whatever prefix we have and quote the rest
{ res = compl.map(function (a) [util.escapeString(a[0].substr(offset), last), a[1]]);
res.forEach(function strEscape(a) a[0] = util.escapeString(a[0].substr(offset), last));
}
else // We're not looking for a quoted string, so filter out anything that's not a valid identifier else // We're not looking for a quoted string, so filter out anything that's not a valid identifier
{ res = compl.filter(function isIdent(a) /^[\w$][\w\d$]*$/.test(a[0]));
res = res.filter(function isIdent(a) /^[\w$][\w\d$]*$/.test(a[0])); if (!anchored)
} res = res.filter(function ([k]) util.compareIgnoreCase(k.substr(0, key.length), key));
return res; context.completions = res;
} }
this.eval = function eval(arg, key, tmp) this.eval = function eval(arg, key, tmp)
@@ -505,7 +586,6 @@ function Completion() //{{{
{ {
if (e.message != "Invalid JS") if (e.message != "Invalid JS")
liberator.reportError(e); liberator.reportError(e);
// liberator.dump(util.escapeString(string) + ": " + e + "\n" + e.stack);
lastIdx = 0; lastIdx = 0;
return; return;
} }
@@ -572,9 +652,15 @@ function Completion() //{{{
{ {
for (let [,obj] in Iterator(objects)) for (let [,obj] in Iterator(objects))
{ {
let ctxt = this.context.fork(obj[1], top[OFFSET]); obj[3] = compl || this.objectKeys(obj);
ctxt.title = [obj[1]]; this.context.fork(obj[1], top[OFFSET], this.filter, this,
ctxt.items = this.filter(compl || this.objectKeys(obj), key + (string || ""), last, key.length); obj[3], obj[1], true, key + (string || ""), last, key.length);
}
for (let [,obj] in Iterator(objects))
{
obj[1] += " (substrings)";
this.context.fork(obj[1], top[OFFSET], this.filter, this,
obj[3], obj[1], false, key + (string || ""), last, key.length);
} }
} }
@@ -723,8 +809,9 @@ function Completion() //{{{
for (let [,item] in Iterator(list)) for (let [,item] in Iterator(list))
{ {
var complist = item[0] instanceof Array ? item[0] // FIXME: Temporary kludge
: [item[0]]; let text = item.item ? item.item[0] || item.text : item[0];
var complist = text instanceof Array ? text : [text];
for (let [,compitem] in Iterator(complist)) for (let [,compitem] in Iterator(complist))
{ {
let str = !ignorecase ? compitem : String(compitem).toLowerCase(); let str = !ignorecase ? compitem : String(compitem).toLowerCase();
@@ -732,15 +819,14 @@ function Completion() //{{{
if (str.indexOf(filter) == -1) if (str.indexOf(filter) == -1)
continue; continue;
filtered.push([compitem, item[1], favicon ? item[2] : null]); item.text = compitem;
filtered.push(item);
if (longest) if (longest)
buildSubstrings(str, filter); buildSubstrings(str, filter);
break; break;
} }
} }
if (options.get("wildoptions").has("sort"))
filtered = filtered.sort(function (a, b) util.compareIgnoreCase(a[0], b[0]));;
return filtered; return filtered;
} }
@@ -755,14 +841,15 @@ function Completion() //{{{
for (let [,item] in Iterator(list)) for (let [,item] in Iterator(list))
{ {
var complist = item[0] instanceof Array ? item[0] let text = item.item ? item.item[0] || item.text : item[0];
: [item[0]]; var complist = text instanceof Array ? text : [text];
for (let [,compitem] in Iterator(complist)) for (let [,compitem] in Iterator(complist))
{ {
if (compitem.indexOf(filter) != 0) if (compitem.substr(0, filter.length) != filter)
continue; continue;
filtered.push([compitem, item[1], favicon ? item[2] : null]); item.text = compitem;
filtered.push(item);
if (longest) if (longest)
{ {
@@ -780,8 +867,6 @@ function Completion() //{{{
break; break;
} }
} }
if (options.get("wildoptions").has("sort"))
filtered = filtered.sort(function (a, b) util.compareIgnoreCase(a[0], b[0]));;
return filtered; return filtered;
} }
@@ -808,17 +893,23 @@ function Completion() //{{{
// returns the longest common substring // returns the longest common substring
// used for the 'longest' setting for wildmode // used for the 'longest' setting for wildmode
get longestSubstring () substrings.reduce(function (a, b) a.length > b.length ? a : b, ""), get longestSubstring() substrings.reduce(function (a, b) a.length > b.length ? a : b, ""),
get substrings() substrings.slice(), get substrings() substrings.slice(),
runCompleter: function (name, filter)
{
let context = new CompletionContext(filter);
context.__defineGetter__("background", function () false);
context.__defineSetter__("background", function () false);
this[name](context);
return context.items.map(function (i) i.item);
},
// generic filter function, also builds substrings needed // generic filter function, also builds substrings needed
// for :set wildmode=list:longest, if necessary // for :set wildmode=list:longest, if necessary
filter: function filter(array, filter, matchFromBeginning, favicon) filter: function filter(array, filter, matchFromBeginning, favicon)
{ {
if (!filter)
return [[a[0], a[1], favicon ? a[2] : null] for each (a in array)];
let result; let result;
if (matchFromBeginning) if (matchFromBeginning)
result = buildLongestStartingSubstring(array, filter, favicon); result = buildLongestStartingSubstring(array, filter, favicon);
@@ -827,16 +918,6 @@ function Completion() //{{{
return result; return result;
}, },
cached: function cached(key, filter, generate, method)
{
if (!filter && cacheFilter[key] || filter.indexOf(cacheFilter[key]) != 0)
cacheResults[key] = generate(filter);
cacheFilter[key] = filter;
if (cacheResults[key].length)
return cacheResults[key] = this[method].apply(this, [cacheResults[key], filter].concat(Array.slice(arguments, 4)));
return [];
},
// cancel any ongoing search // cancel any ongoing search
cancel: function cancel() cancel: function cancel()
{ {
@@ -928,10 +1009,7 @@ function Completion() //{{{
itemsStr = itemsStr.toLowerCase(); itemsStr = itemsStr.toLowerCase();
} }
if (filter.split(/\s+/).every(function strIndex(str) itemsStr.indexOf(str) > -1)) return filter.split(/\s+/).every(function strIndex(str) itemsStr.indexOf(str) > -1);
return true;
return false;
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -944,16 +1022,14 @@ function Completion() //{{{
{ {
return { return {
start: 0, start: 0,
get items() { items: bookmarks.get(filter).map(function (bmark) {
return bookmarks.get(filter).map(function (bmark) {
// temporary, until we have moved all completions to objects // temporary, until we have moved all completions to objects
bmark[0] = bmark.url; bmark[0] = bmark.url;
bmark[1] = bmark.title; bmark[1] = bmark.title;
bmark.text = bmark.url; bmark.text = bmark.url;
return bmark; return bmark;
}); })
},
}; };
}, },
@@ -1017,22 +1093,18 @@ function Completion() //{{{
let schemes = []; let schemes = [];
let rtp = options["runtimepath"].split(","); let rtp = options["runtimepath"].split(",");
rtp.forEach(function (path) { let schemes = rtp.map(function (path) // FIXME: Now! Very, very broken.
// FIXME: Now! Very, very broken. [[c[0].replace(/\.vimp$/, ""), ""]
schemes = schemes.concat([[c[0].replace(/\.vimp$/, ""), ""]
for each (c in completion.file(path + "/colors/", true)[1])]); for each (c in completion.file(path + "/colors/", true)[1])]);
});
return [0, completion.filter(schemes, filter)]; return [0, completion.filter(util.Array.flatten(schemes), filter)];
}, },
command: function command(context) command: function command(context)
{ {
context.title = ["Command"]; context.title = ["Command"];
if (!context.filter) context.anchored = true;
context.items = [[c.name, c.description] for (c in commands)]; context.completions = [[c.longNames, c.description] for (c in commands)];
else
context.items = this.filter([[c.longNames, c.description] for (c in commands)], context.filter, true);
}, },
dialog: function dialog(filter) [0, this.filter(config.dialogs, filter)], dialog: function dialog(filter) [0, this.filter(config.dialogs, filter)],
@@ -1040,7 +1112,7 @@ function Completion() //{{{
directory: function directory(context, tail) directory: function directory(context, tail)
{ {
this.file(context, tail); this.file(context, tail);
context.items = context.items.filter(function (i) i[1] == "Directory"); context.completions = context.completions.filter(function (i) i[1] == "Directory");
}, },
environment: function environment(filter) environment: function environment(filter)
@@ -1050,10 +1122,7 @@ function Completion() //{{{
lines.pop(); lines.pop();
let vars = lines.map(function (line) { let vars = lines.map(function (line) (line.match(/([^=]+)=(.+)/) || []).slice(1));
let matches = line.match(/([^=]+)=(.+)/) || [];
return [matches[1], matches[2]];
});
return [0, this.filter(vars, filter)]; return [0, this.filter(vars, filter)];
}, },
@@ -1075,7 +1144,6 @@ function Completion() //{{{
let [count, cmd, special, args] = commands.parseCommand(context.filter); let [count, cmd, special, args] = commands.parseCommand(context.filter);
let [, prefix, junk] = context.filter.match(/^(:*\d*)\w*(.?)/) || []; let [, prefix, junk] = context.filter.match(/^(:*\d*)\w*(.?)/) || [];
context.advance(prefix.length) context.advance(prefix.length)
context.items = []; // XXX
if (!junk) if (!junk)
return this.command(context); return this.command(context);
@@ -1090,7 +1158,6 @@ function Completion() //{{{
args = command.parseArgs(cmdContext.filter, argContext); args = command.parseArgs(cmdContext.filter, argContext);
if (args) if (args)
{ {
// XXX, XXX, XXX
if (!args.completeOpt && command.completer) if (!args.completeOpt && command.completer)
{ {
cmdContext.advance(args.completeStart); cmdContext.advance(args.completeStart);
@@ -1101,12 +1168,12 @@ function Completion() //{{{
{ {
cmdContext.advance(compObject.start); cmdContext.advance(compObject.start);
cmdContext.title = ["Completions"]; cmdContext.title = ["Completions"];
cmdContext.items = compObject.items; cmdContext.filterFunc = function (k) k;
cmdContext.completions = compObject.items;
} }
} }
cmdContext.updateAsync = true; context.updateAsync = true;
} }
//liberator.dump([[v.name, v.offset, v.items.length, v.hasItems] for each (v in context.contexts)]);
} }
}, },
@@ -1117,65 +1184,53 @@ function Completion() //{{{
let [dir] = context.filter.match(/^(?:.*[\/\\])?/); let [dir] = context.filter.match(/^(?:.*[\/\\])?/);
// dir == "" is expanded inside readDirectory to the current dir // dir == "" is expanded inside readDirectory to the current dir
let generate = function generate() context.title = ["Path", "Type"];
if (tail)
context.advance(dir.length);
context.anchored = true;
context.key = dir;
context.generate = function generate()
{ {
let files = [], mapped = []; context.cache.dir = dir;
try try
{ {
dir = dir.replace("\\ ", " ", "g"); let files = io.readDirectory(dir, true);
files = io.readDirectory(dir, true);
if (options["wildignore"]) if (options["wildignore"])
{ {
let wigRegexp = RegExp("(^" + options["wildignore"].replace(",", "|", "g") + ")$"); let wigRegexp = RegExp("(^" + options["wildignore"].replace(",", "|", "g") + ")$");
files = files.filter(function (f) f.isDirectory() || !wigRegexp.test(f.leafName)) files = files.filter(function (f) f.isDirectory() || !wigRegexp.test(f.leafName))
} }
mapped = files.map( return files.map(
function (file) [(tail ? file.leafName : dir + file.leafName).replace(" ", "\\ ", "g"), function (file) [(tail ? file.leafName : dir + file.leafName).replace(" ", "\\ ", "g"),
file.isDirectory() ? "Directory" : "File"] file.isDirectory() ? "Directory" : "File"]
); );
} }
catch (e) {} catch (e) {}
return [];
return mapped;
}; };
context.title = ["Path", "Type"];
if (tail)
context.advance(dir.length);
context.items = this.cached("file-" + dir, context.filter, generate, "filter", true);
}, },
help: function help(filter) help: function help(context)
{ {
let res = []; context.title = ["Help"];
context.background = true;
for (let [, file] in Iterator(config.helpFiles)) context.generate = function ()
{ {
try let res = config.helpFiles.map(function (file) {
{ let resp = util.httpGet("chrome://liberator/locale/" + file);
var xmlhttp = new XMLHttpRequest(); if (!resp)
xmlhttp.open("GET", "chrome://liberator/locale/" + file, false); return [];
xmlhttp.send(null); let doc = resp.responseXML;
return Array.map(doc.getElementsByClassName("tag"),
function (elem) [elem.textContent, file]);
});
return util.Array.flatten(res);
} }
catch (e)
{
liberator.log("Error opening chrome://liberator/locale/" + file, 1);
continue;
}
let doc = xmlhttp.responseXML;
res.push(Array.map(doc.getElementsByClassName("tag"),
function (elem) [elem.textContent, file]));
}
return [0, this.filter(util.Array.flatten(res), filter)];
}, },
highlightGroup: function highlightGroup(filter) commands.get("highlight").completer(filter), // XXX
get javascriptCompleter() javascript, get javascriptCompleter() javascript,
javascript: function _javascript(context) javascript: function _javascript(context)
@@ -1200,17 +1255,25 @@ function Completion() //{{{
{ {
let [, keyword, space, args] = context.filter.match(/^\s*(\S*)(\s*)(.*)$/); let [, keyword, space, args] = context.filter.match(/^\s*(\S*)(\s*)(.*)$/);
let keywords = bookmarks.getKeywords(); let keywords = bookmarks.getKeywords();
let engines = this.filter(keywords.concat(bookmarks.getSearchEngines()), context.filter, false, true); let engines = bookmarks.getSearchEngines();
context.title = ["Search Keywords"]; context.title = ["Search Keywords"];
context.items = engines; context.completions = keywords.concat(engines);
context.anchored = true;
// TODO: Simplify. if (!space)
for (let [,item] in Iterator(keywords)) return;
{
let name = item.keyword; context.fork("suggest", keyword.length + space.length, this.searchEngineSuggest, this,
if (space && keyword == name && item.url.indexOf("%s") > -1) keyword, true);
context.fork(name, name.length + space.length, function (context) {
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.title = [keyword + " Quick Search"];
context.background = true;
context.anchored = true;
context.generate = function () {
let [begin, end] = item.url.split("%s"); let [begin, end] = item.url.split("%s");
let history = modules.history.service; let history = modules.history.service;
let query = history.getNewQuery(); let query = history.getNewQuery();
@@ -1221,22 +1284,10 @@ function Completion() //{{{
opts.resultType = opts.RESULTS_AS_URI; opts.resultType = opts.RESULTS_AS_URI;
opts.queryType = opts.QUERY_TYPE_HISTORY; opts.queryType = opts.QUERY_TYPE_HISTORY;
context.title = [keyword + " Quick Search"];
function setItems()
{
context.items = completion.filter(context.cache.items, args, false, true);
}
if (context.cache.items)
setItems();
else
{
context.incomplete = true;
liberator.callFunctionInThread(null, function () {
let results = history.executeQuery(query, opts); let results = history.executeQuery(query, opts);
let root = results.root; let root = results.root;
root.containerOpen = true; root.containerOpen = true;
context.cache.items = util.map(util.range(0, root.childCount), function (i) { let result = util.map(util.range(0, root.childCount), function (i) {
let child = root.getChild(i); let child = root.getChild(i);
let rest = child.uri.length - end.length; let rest = child.uri.length - end.length;
let query = child.uri.substring(begin.length, rest); let query = child.uri.substring(begin.length, rest);
@@ -1246,61 +1297,43 @@ function Completion() //{{{
child.icon]; child.icon];
}).filter(function (k) k); }).filter(function (k) k);
root.containerOpen = false; root.containerOpen = false;
context.incomplete = false; return result;
setItems(); };
}); });
}
});
}
}, },
// XXX: Move to bookmarks.js? searchEngineSuggest: function searchEngineSuggest(context, engineAliases, kludge)
searchEngineSuggest: function searchEngineSuggest(context, engineAliases)
{ {
if (!filter) if (!context.filter)
return [0, []]; return;
let engineList = (engineAliases || options["suggestengines"] || "google").split(",");
let responseType = "application/x-suggestions+json";
let ss = Components.classes["@mozilla.org/browser/search-service;1"] let ss = Components.classes["@mozilla.org/browser/search-service;1"]
.getService(Components.interfaces.nsIBrowserSearchService); .getService(Components.interfaces.nsIBrowserSearchService);
let matches = query.match(RegExp("^\s*(" + name + "\\s+)(.*)$")) || []; let engineList = (engineAliases || options["suggestengines"] || "google").split(",");
if (matches[1])
context.advance(matches[1].length);
query = context.filter;
let completions = []; let completions = [];
engineList.forEach(function (name) { engineList.forEach(function (name) {
let engine = ss.getEngineByAlias(name); let engine = ss.getEngineByAlias(name);
if (!engine)
if (engine && engine.supportsResponseType(responseType))
var queryURI = engine.getSubmission(query, responseType).uri.asciiSpec;
else
return; return;
let [, word] = /^\s*(\S+)/.exec(context.filter) || [];
let xhr = new XMLHttpRequest(); if (!kludge && word == name) // FIXME: Check for matching keywords
xhr.open("GET", queryURI, false);
xhr.send(null);
let json = Components.classes["@mozilla.org/dom/json;1"]
.createInstance(Components.interfaces.nsIJSON);
let results = json.decode(xhr.responseText)[1];
if (!results)
return; return;
let ctxt = context.fork(name, 0);
let ctxt = context.fork(engine.name, (matches[1] || "").length); ctxt.title = [engine.description + " Suggestions"];
ctxt.title = [engine.name + " Suggestions"]; ctxt.regenerate = true;
// make sure we receive strings, otherwise a man-in-the-middle attack ctxt.background = true;
// could return objects which toString() method could be called to ctxt.generate = function () bookmarks.getSuggestions(name, this.filter);
// execute untrusted code
ctxt.items = [[item, ""] for ([k, item] in results) if (typeof item == "string")];
}); });
}, },
shellCommand: function shellCommand(filter) shellCommand: function shellCommand(context)
{ {
let generate = function generate() context.title = ["Shell Command", "Path"];
context.generate = function ()
{ {
liberator.dump("generate");
const environmentService = Components.classes["@mozilla.org/process/environment;1"] const environmentService = Components.classes["@mozilla.org/process/environment;1"]
.getService(Components.interfaces.nsIEnvironment); .getService(Components.interfaces.nsIEnvironment);
@@ -1312,17 +1345,13 @@ function Completion() //{{{
let dir = io.getFile(dirName); let dir = io.getFile(dirName);
if (dir.exists() && dir.isDirectory()) if (dir.exists() && dir.isDirectory())
{ {
io.readDirectory(dir).forEach(function (file) { commands.push([[file.leafName, dir.path] for ([i, file] in Iterator(io.readDirectory(dir)))
if (file.isFile() && file.isExecutable()) if (file.isFile() && file.isExecutable())]);
commands.push([file.leafName, dir.path]);
});
} }
} }
return commands; return util.Array.flatten(commands);
} }
return [0, this.cached("shell-command", filter, generate, "filter")];
}, },
sidebar: function sidebar(filter) sidebar: function sidebar(filter)
@@ -1341,14 +1370,14 @@ function Completion() //{{{
// unify split style sheets // unify split style sheets
completions.forEach(function (stylesheet) { completions.forEach(function (stylesheet) {
for (let i = 0; i < completions.length; i++) completions = completions.filter(function (completion) {
if (stylesheet[0] == completion[0] && stylesheet[1] != completion[1])
{ {
if (stylesheet[0] == completions[i][0] && stylesheet[1] != completions[i][1]) stylesheet[1] += ", " + completion[1];
{ return false;
stylesheet[1] += ", " + completions[i][1];
completions.splice(i, 1);
}
} }
return true;
});
}); });
return [0, this.filter(completions, filter)]; return [0, this.filter(completions, filter)];
@@ -1374,14 +1403,8 @@ function Completion() //{{{
b: function b(context) b: function b(context)
{ {
context.title = ["Bookmark", "Title"]; context.title = ["Bookmark", "Title"];
context.createRow = function createRow(context, item, class) context.format = bookmarks.format;
{ context.completions = bookmarks.get(context.filter)
// FIXME
if (class)
return template.completionRow(context, item, class);
return template.bookmarkItem(item);
}
context.items = bookmarks.get(context.filter)
}, },
l: function l(context) l: function l(context)
{ {
@@ -1389,15 +1412,16 @@ function Completion() //{{{
return return
context.title = ["Smart Completions"]; context.title = ["Smart Completions"];
context.incomplete = true; context.incomplete = true;
context.hasItems = context.items.length > 0; // XXX context.hasItems = context.completions.length > 0; // XXX
context.filterFunc = function (items) items;
let timer = new util.Timer(50, 100, function (result) { let timer = new util.Timer(50, 100, function (result) {
context.items = [ context.completions = [
[result.getValueAt(i), result.getCommentAt(i), result.getImageAt(i)] { 0: result.getValueAt(i), 1: result.getCommentAt(i), icon: result.getImageAt(i) }
for (i in util.range(0, result.matchCount)) for (i in util.range(0, result.matchCount))
]; ];
context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING; context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
let filter = context.filter; let filter = context.filter;
context.items.forEach(function ([item]) buildSubstrings(item, filter)); context.completions.forEach(function ([item]) buildSubstrings(item, filter));
}); });
completionService.stopSearch(); completionService.stopSearch();
completionService.startSearch(context.filter, "", context.result, { completionService.startSearch(context.filter, "", context.result, {
@@ -1408,9 +1432,9 @@ function Completion() //{{{
timer.flush(); timer.flush();
} }
}); });
} }
}; };
// Will, and should, throw an error if !(c in opts)
Array.forEach(complete || options["complete"], Array.forEach(complete || options["complete"],
function (c) context.fork(c, 0, opts[c], completion)); function (c) context.fork(c, 0, opts[c], completion));
}, },
@@ -1432,11 +1456,10 @@ function Completion() //{{{
userMapping: function userMapping(context, args, modes) userMapping: function userMapping(context, args, modes)
{ {
liberator.dump(args);
if (args.completeArg == 0) if (args.completeArg == 0)
{ {
let maps = [[m.names[0], ""] for (m in mappings.getUserIterator(modes))]; let maps = [[m.names[0], ""] for (m in mappings.getUserIterator(modes))];
context.items = this.filter(maps, args.arguments[0]); context.completions = this.filter(maps, args.arguments[0]);
} }
} }
// }}} // }}}

View File

@@ -339,7 +339,7 @@ function IO() //{{{
}, },
{ {
bang: true, bang: true,
completer: function (context) completion.shellCommand(context.filter), completer: function (context) completion.shellCommand(context),
literal: true literal: true
}); });

View File

@@ -308,7 +308,7 @@ const liberator = (function () //{{{
}, },
{ {
bang: true, bang: true,
completer: function (context) completion.help(context.filter), completer: function (context) completion.help(context),
literal: true literal: true
}); });
@@ -893,17 +893,17 @@ const liberator = (function () //{{{
}, 500); }, 500);
} }
var [, items] = completion.help(topic); var items = completion.runCompleter("help", topic);
var partialMatch = -1; var partialMatch = -1;
for (let i = 0; i < items.length; i++) for (let [i, item] in Iterator(items))
{ {
if (items[i][0] == topic) if (item[0] == topic)
{ {
jumpToTag(items[i][1], items[i][0]); jumpToTag(item[1], item[0]);
return; return;
} }
else if (partialMatch == -1 && items[i][0].indexOf(topic) > -1) else if (partialMatch == -1 && item[0].indexOf(topic) > -1)
{ {
partialMatch = i; partialMatch = i;
} }

View File

@@ -750,9 +750,8 @@ function Options() //{{{
let opt = parseOpt(filter, modifiers); let opt = parseOpt(filter, modifiers);
let option = opt.option; let option = opt.option;
commandline.highlight(0, 0, "SPELLCHECK"); if (!option)
if (!option) /* FIXME: Kludge. */ context.highlight(0, name.length, "SPELLCHECK");
commandline.highlight(0, name.length, "SPELLCHECK");
if (opt.get || opt.reset || !option || prefix) if (opt.get || opt.reset || !option || prefix)
return [0, []]; return [0, []];

View File

@@ -32,10 +32,10 @@ function Highlights(name, store, serial)
CompItem CompItem
CompItem[selected] background: yellow; CompItem[selected] background: yellow;
CompItem>* padding: 0 .5ex; CompItem>* padding: 0 .5ex;
CompIcon width: 16px; min-width: 16px; CompIcon width: 16px; min-width: 16px; display: inline-block; margin-right: .5ex;
CompIcon>img max-width: 16px; max-height: 16px; vertical-align: middle; CompIcon>img max-width: 16px; max-height: 16px; vertical-align: middle;
CompResult width: 45%; overflow: hidden; CompResult width: 45%; overflow: hidden;
CompDesc color: gray; CompDesc color: gray; width: 50%;
Indicator color: blue; Indicator color: blue;
Filter font-weight: bold; Filter font-weight: bold;
@@ -438,8 +438,7 @@ liberator.registerObserver("load_commands", function ()
compl.push([content.location.href, "Current URL"]); compl.push([content.location.href, "Current URL"]);
} }
catch (e) {} catch (e) {}
compl = compl.concat([[s, ""] for each (s in styles.sites)]) context.completions = compl.concat([[s, ""] for each (s in styles.sites)])
context.items = completion.filter(compl, args.arguments[0]);
} }
}, },
hereDoc: true, hereDoc: true,

View File

@@ -34,36 +34,42 @@ const template = {
completionRow: function completionRow(context, item, class) completionRow: function completionRow(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") if (typeof icon == "function")
icon = icon(); icon = icon();
if (class)
{
var [text, desc] = item;
}
else
{
var text = context.process[0](item, item.text || item.item[context.keys[0]]);
var desc = context.process[1](item, item.item[context.keys[1]]);
}
return <ul class={class || "hl-CompItem"}> return <ul class={class || "hl-CompItem"}>
<li class="hl-CompIcon">{icon ? <img src={icon}/> : <></>}</li> <li class="hl-CompResult">{text || ""}</li>
<li class="hl-CompResult">{text}</li> <li class="hl-CompDesc">{desc || ""}</li>
<li class="hl-CompDesc">{description}</li>
</ul>; </ul>;
}, },
bookmarkDescription: function (item, text)
<>
<a href="#" class="hl-URL">{text}</a>&#160;
{
!(item.item.extra.length) ? "" :
<span class="extra-info">
({
template.map(item.item.extra, function (e)
<>{e[0]}: <span class={e[2]}>{e[1]}</span></>,
<>&#xa0;</>/* Non-breaking space */)
})
</span>
}
</>,
icon: function (item, text) <><span class="hl-CompIcon">{item.item.icon ? <img src={item.item.icon}/> : <></>}</span>{text}</>,
filter: function (str) <span class="hl-Filter">{str}</span>, filter: function (str) <span class="hl-Filter">{str}</span>,
// if "processStrings" is true, any passed strings will be surrounded by " and // if "processStrings" is true, any passed strings will be surrounded by " and
@@ -114,11 +120,10 @@ const template = {
highlightFilter: function highlightFilter(str, filter, highlight) highlightFilter: function highlightFilter(str, filter, highlight)
{ {
if (typeof str == "xml")
return str;
return this.highlightSubstrings(str, (function () return this.highlightSubstrings(str, (function ()
{ {
if (filter.length == 0)
return;
let lcstr = String.toLowerCase(str); let lcstr = String.toLowerCase(str);
let lcfilter = filter.toLowerCase(); let lcfilter = filter.toLowerCase();
let start = 0; let start = 0;
@@ -132,12 +137,9 @@ const template = {
highlightRegexp: function highlightRegexp(str, re, highlight) highlightRegexp: function highlightRegexp(str, re, highlight)
{ {
if (typeof str == "xml")
return str;
return this.highlightSubstrings(str, (function () return this.highlightSubstrings(str, (function ()
{ {
while (res = re.exec(str)) while (res = re.exec(str) && res[0].length)
yield [res.index, res[0].length]; yield [res.index, res[0].length];
})(), highlight || template.filter); })(), highlight || template.filter);
}, },

View File

@@ -1180,28 +1180,6 @@ function CommandLine() //{{{
} }
}, },
highlight: function highlight(start, end, type)
{
// FIXME: Kludge.
try // Firefox <3.1 doesn't have repaintSelection
{
const selType = Components.interfaces.nsISelectionController["SELECTION_" + type];
let editor = document.getElementById("liberator-commandline-command")
.inputField.editor;
let sel = editor.selectionController.getSelection(selType);
sel.removeAllRanges();
let range = editor.selection.getRangeAt(0).cloneRange();
let n = this.getCommand().indexOf(" ") + 1;
let node = range.startContainer;
range.setStart(node, start + n);
range.setEnd(node, end + n);
sel.addRange(range);
editor.selectionController.repaintSelection(selType);
}
catch (e) {}
},
updateMorePrompt: function updateMorePrompt(force, showHelp) updateMorePrompt: function updateMorePrompt(force, showHelp)
{ {
let win = multilineOutputWidget.contentWindow; let win = multilineOutputWidget.contentWindow;
@@ -1356,12 +1334,12 @@ function ItemList(id) //{{{
// do a full refill of the list: // do a full refill of the list:
XML.ignoreWhitespace = true; XML.ignoreWhitespace = true;
let off = 0; let off = 0;
function range(context) function getItems(context)
{ {
let len = context.items.length; let len = context.items.length;
let start = off; let start = off;
off += len; off += len;
return util.range(Math.max(offset - start, 0), Math.min(endIndex - start, len)); return context.getItems(offset - start, endIndex - start);
} }
let xml = <div class="ex-command-output hl-Normal" style="white-space: nowrap"> let xml = <div class="ex-command-output hl-Normal" style="white-space: nowrap">
@@ -1372,11 +1350,11 @@ function ItemList(id) //{{{
: <></> : <></>
} }
{ {
template.map(items.contextList, function (context) context.hasItems ? template.map(items.contextList, function (context) context.items.length ?
<> <>
{ context.createRow(context, context.title || {}, "hl-CompTitle") } { context.createRow(context, context.title || [], "hl-CompTitle") }
{ {
template.map(range(context), function (i) context.createRow(context, context.items[i])) template.map(getItems(context), function (item) context.createRow(context, item))
} }
</> </>
: undefined) : undefined)

View File

@@ -272,6 +272,21 @@ const util = { //{{{
return ret; return ret;
}, },
httpGet: function (url)
{
try
{
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", url, false);
xmlhttp.send(null);
return xmlhttp;
}
catch (e)
{
liberator.log("Error opening " + url, 1);
}
},
map: function (obj, fn) map: function (obj, fn)
{ {
let ary = []; let ary = [];
@@ -359,7 +374,7 @@ const util = { //{{{
} }
else else
{ {
while (start >= end) while (start > end)
yield --start; yield --start;
} }
}, },

View File

@@ -20,8 +20,8 @@ email=stubenschrott@gmx.net
# #
[replacements] [replacements]
LOGO=<center>image:chrome://liberator/content/vimperator.png[Vimperator]</center> LOGO=<center>image:chrome://liberator2/content/vimperator.png[Vimperator]</center>
HEADER=<div style="float: right; padding-top: 10px;"><form action="https://www.paypal.com/cgi-bin/webscr" method="post"><fieldset class="paypal"> <input type="hidden" name="cmd" value="_s-xclick"/> <input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but21.gif" name="submit" alt="Make payments with PayPal - it\'s fast, free and secure!"/> <img alt="" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1"/> <input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----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-----END PKCS7-----"/> </fieldset></form></div>image:chrome://liberator/content/vimperator.png[Vimperator] HEADER=<div style="float: right; padding-top: 10px;"><form action="https://www.paypal.com/cgi-bin/webscr" method="post"><fieldset class="paypal"> <input type="hidden" name="cmd" value="_s-xclick"/> <input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but21.gif" name="submit" alt="Make payments with PayPal - it\'s fast, free and secure!"/> <img alt="" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1"/> <input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----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-----END PKCS7-----"/> </fieldset></form></div>image:chrome://liberator2/content/vimperator.png[Vimperator]
\[count\]=<span class="argument">&#91;count&#93;</span> \[count\]=<span class="argument">&#91;count&#93;</span>
\[args\]=<span class="argument">&#91;args&#93;</span> \[args\]=<span class="argument">&#91;args&#93;</span>
\[arg\]=<span class="argument">&#91;arg&#93;</span> \[arg\]=<span class="argument">&#91;arg&#93;</span>

BIN
webcontent/vimperator.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B