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

move some completion code to completion.js

This commit is contained in:
Doug Kearns
2008-10-07 15:32:48 +00:00
parent d0a7df74bc
commit 01e89bc6d8
8 changed files with 329 additions and 320 deletions

View File

@@ -283,7 +283,7 @@ liberator.Bookmarks = function () //{{{
}, },
{ {
bang: true, bang: true,
completer: function (filter) [0, liberator.bookmarks.get(filter)], completer: function (filter) liberator.completion.bookmark(filter),
options: [[["-tags", "-T"], liberator.commands.OPTION_LIST]] options: [[["-tags", "-T"], liberator.commands.OPTION_LIST]]
}); });
@@ -296,7 +296,7 @@ liberator.Bookmarks = function () //{{{
liberator.echo(deletedCount + " bookmark(s) with url `" + url + "' deleted", liberator.commandline.FORCE_SINGLELINE); liberator.echo(deletedCount + " bookmark(s) with url `" + url + "' deleted", liberator.commandline.FORCE_SINGLELINE);
}, },
{ completer: function (filter) [0, liberator.bookmarks.get(filter)] }); { completer: function (filter) liberator.completion.bookmark(filter) });
/////////////////////////////////////////////////////////////////////////////}}} /////////////////////////////////////////////////////////////////////////////}}}
////////////////////// PUBLIC SECTION ////////////////////////////////////////// ////////////////////// PUBLIC SECTION //////////////////////////////////////////
@@ -696,7 +696,7 @@ liberator.History = function () //{{{
function (args, special) { liberator.history.list(args, special); }, function (args, special) { liberator.history.list(args, special); },
{ {
bang: true, bang: true,
completer: function (filter) [0, liberator.history.get(filter)] completer: function (filter) liberator.completion.history(filter)
}); });
/////////////////////////////////////////////////////////////////////////////}}} /////////////////////////////////////////////////////////////////////////////}}}

View File

@@ -380,10 +380,10 @@ liberator.Buffer = function () //{{{
"number", 1, "number", 1,
{ {
completer: function (filter) [0, [ completer: function (filter) [0, [
["0", "Don't show link destination"], ["0", "Don't show link destination"],
["1", "Show the link in the status line"], ["1", "Show the link in the status line"],
["2", "Show the link in the command line"] ["2", "Show the link in the command line"]
]], ]],
validator: function (value) value >= 0 && value <= 2 validator: function (value) value >= 0 && value <= 2
}); });
@@ -805,6 +805,7 @@ liberator.Buffer = function () //{{{
liberator.buffer.highlight(key, css, special); liberator.buffer.highlight(key, css, special);
}, },
{ {
// TODO: add this as a standard highlight completion function?
completer: function (filter) [0, liberator.completion.filter([[v, ""] for ([k, v] in Iterator(highlightClasses))], filter)], completer: function (filter) [0, liberator.completion.filter([[v, ""] for ([k, v] in Iterator(highlightClasses))], filter)],
hereDoc: true, hereDoc: true,
bang: true, bang: true,

View File

@@ -320,7 +320,7 @@ liberator.Completion = function () //{{{
|| get(-3, 0, STATEMENTS) == get(-2)[OFFSET]) /* Okay. Is it an array literal? */ || get(-3, 0, STATEMENTS) == get(-2)[OFFSET]) /* Okay. Is it an array literal? */
return [0, []]; /* No. Nothing to do. */ return [0, []]; /* No. Nothing to do. */
/* /*
* str = "foo[bar + 'baz" * str = "foo[bar + 'baz"
* obj = "foo" * obj = "foo"
* key = "bar + ''" * key = "bar + ''"
@@ -510,267 +510,6 @@ liberator.Completion = function () //{{{
return cacheResults[key]; return cacheResults[key];
}, },
autocommand: function (filter)
{
let autoCmds = liberator.config.autocommands;
return [0, this.filter(autoCmds, filter)];
},
// FIXME: items shouldn't be [[[a], b]], but [[a, b]] and only mapped if at all for bLCS --mst
buffer: function (filter)
{
var items = [];
var num = getBrowser().browsers.length;
var title, url;
for (let i = 0; i < num; i++)
{
try
{
title = getBrowser().getBrowserAtIndex(i).contentDocument.title;
}
catch (e)
{
title = "";
}
url = getBrowser().getBrowserAtIndex(i).contentDocument.location.href;
if (title.indexOf(filter) == -1 && url.indexOf(filter) == -1 &&
(i + 1).toString().indexOf(filter) == -1)
continue;
if (title.indexOf(filter) != -1 || url.indexOf(filter) != -1 ||
(i + 1).toString().indexOf(filter) != -1)
{
if (title == "")
title = "(Untitled)";
items.push([[(i + 1) + ": " + title, (i + 1) + ": " + url], url]);
}
}
if (!filter)
return [0, items.map(function (i) [i[0][0], i[1]])];
return [0, buildLongestCommonSubstring(items, filter)];
},
command: function (filter)
{
var completions = [];
if (!filter)
{
for (let command in liberator.commands)
completions.push([command.name, command.description]);
return [0, completions];
}
for (let command in liberator.commands)
completions.push([command.longNames, command.description]);
return [0, buildLongestStartingSubstring(completions, filter)];
},
// TODO: support file:// and \ or / path separators on both platforms
// if "tail" is true, only return names without any directory components
file: function (filter, tail)
{
var dir = "", compl = "";
var matches = filter.match(/^(.*[\/\\])?(.*?)$/);
if (matches)
{
dir = matches[1] || ""; // "" is expanded inside readDirectory to the current dir
compl = matches[2] || "";
}
var files = [], mapped = [];
try
{
files = liberator.io.readDirectory(dir, true);
if (liberator.options["wildignore"])
{
var wigRegexp = new RegExp("(^" + liberator.options["wildignore"].replace(",", "|", "g") + ")$");
files = files.filter(function (f) f.isDirectory() || !wigRegexp.test(f.leafName))
}
mapped = files.map(function (file) [tail ? file.leafName : (dir + file.leafName),
file.isDirectory() ? "Directory" : "File"]);
}
catch (e)
{
return [0, []];
}
if (tail)
return [dir.length, buildLongestStartingSubstring(mapped, compl, true)];
else
return [0, buildLongestStartingSubstring(mapped, filter, true)];
},
javascript: function (str)
{
return javascript.complete(str);
},
macro: function (filter)
{
var macros = [item for (item in liberator.events.getMacros())];
return [0, liberator.completion.filter(macros, filter)];
},
search: function (filter)
{
let results = this.cached("search", filter,
function () Array.concat(liberator.bookmarks.getKeywords().map(function (k) [k[0], k[1], k[3]]),
liberator.bookmarks.getSearchEngines()),
"filter", false, true);
return [0, results];
},
// XXX: Move to bookmarks.js?
searchEngineSuggest: function (filter, engineAliases)
{
if (!filter)
return [0, []];
var engineList = (engineAliases || liberator.options["suggestengines"]).split(",");
var responseType = "application/x-suggestions+json";
var ss = Components.classes["@mozilla.org/browser/search-service;1"]
.getService(Components.interfaces.nsIBrowserSearchService);
var completions = [];
engineList.forEach(function (name) {
var query = filter;
var queryURI;
var engine = ss.getEngineByAlias(name);
var reg = new RegExp("^\s*(" + name + "\\s+)(.*)$");
var matches = query.match(reg);
if (matches)
query = matches[2];
if (engine && engine.supportsResponseType(responseType))
queryURI = engine.getSubmission(query, responseType).uri.asciiSpec;
else
return [0, []];
var xhr = new XMLHttpRequest();
xhr.open("GET", queryURI, false);
xhr.send(null);
var json = Components.classes["@mozilla.org/dom/json;1"]
.createInstance(Components.interfaces.nsIJSON);
var results = json.decode(xhr.responseText)[1];
if (!results)
return [0, []];
results.forEach(function (item) {
// make sure we receive strings, otherwise a man-in-the-middle attack
// could return objects which toString() method could be called to
// execute untrusted code
if (typeof item != "string")
return [0, []];
completions.push([(matches ? matches[1] : "") + item, engine.name + " suggestion"]);
});
});
return [0, completions];
},
stylesheet: function (filter)
{
var completions = liberator.buffer.alternateStyleSheets.map(
function (stylesheet) [stylesheet.title, stylesheet.href || "inline"]
);
// unify split style sheets
completions.forEach(function (stylesheet) {
for (let i = 0; i < completions.length; i++)
{
if (stylesheet[0] == completions[i][0] && stylesheet[1] != completions[i][1])
{
stylesheet[1] += ", " + completions[i][1];
completions.splice(i, 1);
}
}
});
return [0, this.filter(completions, filter)];
},
// filter a list of urls
//
// may consist of search engines, filenames, bookmarks and history,
// depending on the 'complete' option
// if the 'complete' argument is passed like "h", it temporarily overrides the complete option
url: function (filter, complete)
{
var completions = [];
var start = 0;
var skip = filter.match("^(.*" + liberator.options["urlseparator"] + ")(.*)"); // start after the last 'urlseparator'
if (skip)
{
start += skip[1].length;
filter = skip[2];
}
var cpt = complete || liberator.options["complete"];
var suggestEngineAlias = liberator.options["suggestengines"] || "google";
// join all completion arrays together
for (let c in liberator.util.arrayIter(cpt))
{
if (c == "s")
completions.push(this.search(filter)[1]);
else if (c == "f")
completions.push(this.file(filter, false)[1]);
else if (c == "S")
completions.push(this.searchEngineSuggest(filter, suggestEngineAlias)[1]);
else if (c == "b")
completions.push(liberator.bookmarks.get(filter).map(function (a) [a[0], a[1], a[5]]));
else if (c == "h")
completions.push(liberator.history.get(filter));
else if (c == "l" && completionService) // add completions like Firefox's smart location bar
{
completionService.stopSearch();
completionService.startSearch(filter, "", historyResult, {
onSearchResult: function (search, result) {
historyResult = result;
historyTimer.tell();
if (result.searchResult <= result.RESULT_SUCCESS)
historyTimer.flush();
}
});
}
}
completionCache = liberator.util.flatten(completions);
return [start, completionCache.concat(historyCache)];
},
userCommand: function (filter)
{
var commands = liberator.commands.getUserCommands();
commands = commands.map(function (command) [command.name, ""]);
return [0, this.filter(commands, filter)];
},
userMapping: function (filter, modes)
{
// TODO: add appropriate getters to l.mappings
var mappings = [];
for (let map in liberator.mappings.getUserIterator(modes))
mappings.push([map.names[0], ""]);
return [0, this.filter(mappings, filter)];
},
// discard all entries in the 'urls' array, which don't match 'filter // discard all entries in the 'urls' array, which don't match 'filter
// urls must be of type [["url", "title"], [...]] or optionally // urls must be of type [["url", "title"], [...]] or optionally
// [["url", "title", keyword, [tags]], [...]] // [["url", "title", keyword, [tags]], [...]]
@@ -865,6 +604,72 @@ liberator.Completion = function () //{{{
return false; return false;
}, },
////////////////////////////////////////////////////////////////////////////////
////////////////////// COMPLETION TYPES ////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
bookmark: function (filter) [0, liberator.bookmarks.get(filter)],
// FIXME: items shouldn't be [[[a], b]], but [[a, b]] and only mapped if at all for bLCS --mst
buffer: function (filter)
{
var items = [];
var num = getBrowser().browsers.length;
var title, url;
for (let i = 0; i < num; i++)
{
try
{
title = getBrowser().getBrowserAtIndex(i).contentDocument.title;
}
catch (e)
{
title = "";
}
url = getBrowser().getBrowserAtIndex(i).contentDocument.location.href;
if (title.indexOf(filter) == -1 && url.indexOf(filter) == -1 &&
(i + 1).toString().indexOf(filter) == -1)
continue;
if (title.indexOf(filter) != -1 || url.indexOf(filter) != -1 ||
(i + 1).toString().indexOf(filter) != -1)
{
if (title == "")
title = "(Untitled)";
items.push([[(i + 1) + ": " + title, (i + 1) + ": " + url], url]);
}
}
if (!filter)
return [0, items.map(function (i) [i[0][0], i[1]])];
return [0, buildLongestCommonSubstring(items, filter)];
},
command: function (filter)
{
var completions = [];
if (!filter)
{
for (let command in liberator.commands)
completions.push([command.name, command.description]);
return [0, completions];
}
for (let command in liberator.commands)
completions.push([command.longNames, command.description]);
return [0, buildLongestStartingSubstring(completions, filter)];
},
dialog: function (filter) [0, this.filter(liberator.config.dialogs || [], filter)],
event: function (filter) [0, this.filter(liberator.config.autocommands, filter)],
// provides completions for ex commands, including their arguments // provides completions for ex commands, including their arguments
ex: function (str) ex: function (str)
{ {
@@ -889,7 +694,247 @@ liberator.Completion = function () //{{{
[start, completions] = command.completer.call(this, args, special); [start, completions] = command.completer.call(this, args, special);
} }
return [exLength + start, completions]; return [exLength + start, completions];
},
// TODO: support file:// and \ or / path separators on both platforms
// if "tail" is true, only return names without any directory components
file: function (filter, tail)
{
var dir = "", compl = "";
var matches = filter.match(/^(.*[\/\\])?(.*?)$/);
if (matches)
{
dir = matches[1] || ""; // "" is expanded inside readDirectory to the current dir
compl = matches[2] || "";
}
var files = [], mapped = [];
try
{
files = liberator.io.readDirectory(dir, true);
if (liberator.options["wildignore"])
{
var wigRegexp = new RegExp("(^" + liberator.options["wildignore"].replace(",", "|", "g") + ")$");
files = files.filter(function (f) f.isDirectory() || !wigRegexp.test(f.leafName))
}
mapped = files.map(function (file) [tail ? file.leafName : (dir + file.leafName),
file.isDirectory() ? "Directory" : "File"]);
}
catch (e)
{
return [0, []];
}
if (tail)
return [dir.length, buildLongestStartingSubstring(mapped, compl, true)];
else
return [0, buildLongestStartingSubstring(mapped, filter, true)];
},
help: function (filter)
{
var files = liberator.config.helpFiles || [];
var res = [];
for (let i = 0; i < files.length; i++)
{
try
{
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "chrome://" + liberator.config.name.toLowerCase() + "/locale/" + files[i], false);
xmlhttp.send(null);
}
catch (e)
{
liberator.log("Error opening chrome://" + liberator.config.name.toLowerCase() + "/locale/" + files[i], 1);
continue;
}
var doc = xmlhttp.responseXML;
var elems = doc.getElementsByClassName("tag");
for (let j = 0; j < elems.length; j++)
res.push([elems[j].textContent, files[i]]);
}
return [0, this.filter(res, filter)];
},
history: function (filter) [0, liberator.history.get(filter)],
javascript: function (str)
{
return javascript.complete(str);
},
macro: function (filter)
{
var macros = [item for (item in liberator.events.getMacros())];
return [0, this.filter(macros, filter)];
},
search: function (filter)
{
let results = this.cached("search", filter,
function () Array.concat(liberator.bookmarks.getKeywords().map(function (k) [k[0], k[1], k[3]]),
liberator.bookmarks.getSearchEngines()),
"filter", false, true);
return [0, results];
},
// XXX: Move to bookmarks.js?
searchEngineSuggest: function (filter, engineAliases)
{
if (!filter)
return [0, []];
var engineList = (engineAliases || liberator.options["suggestengines"]).split(",");
var responseType = "application/x-suggestions+json";
var ss = Components.classes["@mozilla.org/browser/search-service;1"]
.getService(Components.interfaces.nsIBrowserSearchService);
var completions = [];
engineList.forEach(function (name) {
var query = filter;
var queryURI;
var engine = ss.getEngineByAlias(name);
var reg = new RegExp("^\s*(" + name + "\\s+)(.*)$");
var matches = query.match(reg);
if (matches)
query = matches[2];
if (engine && engine.supportsResponseType(responseType))
queryURI = engine.getSubmission(query, responseType).uri.asciiSpec;
else
return [0, []];
var xhr = new XMLHttpRequest();
xhr.open("GET", queryURI, false);
xhr.send(null);
var json = Components.classes["@mozilla.org/dom/json;1"]
.createInstance(Components.interfaces.nsIJSON);
var results = json.decode(xhr.responseText)[1];
if (!results)
return [0, []];
results.forEach(function (item) {
// make sure we receive strings, otherwise a man-in-the-middle attack
// could return objects which toString() method could be called to
// execute untrusted code
if (typeof item != "string")
return [0, []];
completions.push([(matches ? matches[1] : "") + item, engine.name + " suggestion"]);
});
});
return [0, completions];
},
sidebar: function (filter)
{
var menu = document.getElementById("viewSidebarMenu");
var nodes = [];
for (let i = 0; i < menu.childNodes.length; i++)
nodes.push([menu.childNodes[i].label, ""]);
return [0, this.filter(nodes, filter)];
},
stylesheet: function (filter)
{
var completions = liberator.buffer.alternateStyleSheets.map(
function (stylesheet) [stylesheet.title, stylesheet.href || "inline"]
);
// unify split style sheets
completions.forEach(function (stylesheet) {
for (let i = 0; i < completions.length; i++)
{
if (stylesheet[0] == completions[i][0] && stylesheet[1] != completions[i][1])
{
stylesheet[1] += ", " + completions[i][1];
completions.splice(i, 1);
}
}
});
return [0, this.filter(completions, filter)];
},
// filter a list of urls
//
// may consist of search engines, filenames, bookmarks and history,
// depending on the 'complete' option
// if the 'complete' argument is passed like "h", it temporarily overrides the complete option
url: function (filter, complete)
{
var completions = [];
var start = 0;
var skip = filter.match("^(.*" + liberator.options["urlseparator"] + ")(.*)"); // start after the last 'urlseparator'
if (skip)
{
start += skip[1].length;
filter = skip[2];
}
var cpt = complete || liberator.options["complete"];
var suggestEngineAlias = liberator.options["suggestengines"] || "google";
// join all completion arrays together
for (let c in liberator.util.arrayIter(cpt))
{
if (c == "s")
completions.push(this.search(filter)[1]);
else if (c == "f")
completions.push(this.file(filter, false)[1]);
else if (c == "S")
completions.push(this.searchEngineSuggest(filter, suggestEngineAlias)[1]);
else if (c == "b")
completions.push(liberator.bookmarks.get(filter).map(function (a) [a[0], a[1], a[5]]));
else if (c == "h")
completions.push(liberator.history.get(filter));
else if (c == "l" && completionService) // add completions like Firefox's smart location bar
{
completionService.stopSearch();
completionService.startSearch(filter, "", historyResult, {
onSearchResult: function (search, result) {
historyResult = result;
historyTimer.tell();
if (result.searchResult <= result.RESULT_SUCCESS)
historyTimer.flush();
}
});
}
}
completionCache = liberator.util.flatten(completions);
return [start, completionCache.concat(historyCache)];
},
userCommand: function (filter)
{
var commands = liberator.commands.getUserCommands();
commands = commands.map(function (command) [command.name, ""]);
return [0, this.filter(commands, filter)];
},
userMapping: function (filter, modes)
{
// TODO: add appropriate getters to l.mappings
var mappings = [];
for (let map in liberator.mappings.getUserIterator(modes))
mappings.push([map.names[0], ""]);
return [0, this.filter(mappings, filter)];
} }
// }}}
}; };
//}}} //}}}
}; //}}} }; //}}}

View File

@@ -127,7 +127,7 @@ liberator.AutoCommands = function () //{{{
}, },
{ {
bang: true, bang: true,
completer: function (filter) liberator.completion.autocommand(filter) completer: function (filter) liberator.completion.event(filter)
}); });
// TODO: expand target to all buffers // TODO: expand target to all buffers
@@ -139,7 +139,7 @@ liberator.AutoCommands = function () //{{{
}, },
{ {
argCount: "+", argCount: "+",
completer: function (filter) liberator.completion.autocommand(filter) completer: function (filter) liberator.completion.event(filter)
} }
); );
@@ -175,7 +175,7 @@ liberator.AutoCommands = function () //{{{
{ {
// TODO: Vim actually just displays "No matching autocommands" when no arg is specified // TODO: Vim actually just displays "No matching autocommands" when no arg is specified
argCount: "+", argCount: "+",
completer: function (filter) liberator.completion.autocommand(filter) completer: function (filter) liberator.completion.event(filter)
} }
); );

View File

@@ -241,11 +241,10 @@ const liberator = (function () //{{{
}, },
{ {
argCount: "+", // NOTE: single arg may contain unescaped whitespace argCount: "+", // NOTE: single arg may contain unescaped whitespace
// TODO: add this as a standard menu completion function
completer: function (filter) completer: function (filter)
{ {
var completions = getMenuItems().map( let completions = getMenuItems().map(function (item) [item.fullMenuPath, item.label]);
function (item) [item.fullMenuPath, item.label]
);
return [0, liberator.completion.filter(completions, filter)]; return [0, liberator.completion.filter(completions, filter)];
} }
}); });
@@ -313,7 +312,7 @@ const liberator = (function () //{{{
}, },
{ {
bang: true, bang: true,
completer: function (filter) getHelpCompletions(filter) completer: function (filter) liberator.completion.help(filter)
}); });
liberator.commands.add(["javas[cript]", "js"], liberator.commands.add(["javas[cript]", "js"],
@@ -543,33 +542,6 @@ const liberator = (function () //{{{
}); });
} }
function getHelpCompletions(filter)
{
var files = liberator.config.helpFiles || [];
var res = [];
for (let i = 0; i < files.length; i++)
{
try
{
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "chrome://" + liberator.config.name.toLowerCase() + "/locale/" + files[i], false);
xmlhttp.send(null);
}
catch (e)
{
liberator.log("Error opening chrome://" + liberator.config.name.toLowerCase() + "/locale/" + files[i], 1);
continue;
}
var doc = xmlhttp.responseXML;
var elems = doc.getElementsByClassName("tag");
for (let j = 0; j < elems.length; j++)
res.push([elems[j].textContent, files[i]]);
}
return [0, liberator.completion.filter(res, filter)];
}
// initially hide all GUI, it is later restored unless the user has :set go= or something // initially hide all GUI, it is later restored unless the user has :set go= or something
// similar in his config // similar in his config
function hideGUI() function hideGUI()
@@ -905,7 +877,7 @@ const liberator = (function () //{{{
}, 500); }, 500);
} }
var [, items] = getHelpCompletions(topic); var [, items] = liberator.completion.help(topic);
var partialMatch = -1; var partialMatch = -1;
for (let i = 0; i < items.length; i++) for (let i = 0; i < items.length; i++)

View File

@@ -145,9 +145,9 @@ liberator.Tabs = function () //{{{
completer: function (filter) completer: function (filter)
{ {
return [ return [
["0", "Never show tab bar"], ["0", "Never show tab bar"],
["1", "Show tab bar only if more than one tab is open"], ["1", "Show tab bar only if more than one tab is open"],
["2", "Always show tab bar"] ["2", "Always show tab bar"]
]; ];
}, },
validator: function (value) value >= 0 && value <= 2 validator: function (value) value >= 0 && value <= 2

View File

@@ -1430,9 +1430,9 @@ liberator.StatusLine = function () //{{{
completer: function (filter) completer: function (filter)
{ {
return [ return [
["0", "Never display status line"], ["0", "Never display status line"],
["1", "Display status line only if there are multiple windows"], ["1", "Display status line only if there are multiple windows"],
["2", "Always display status line"] ["2", "Always display status line"]
]; ];
}, },
validator: function (value) value >= 0 && value <= 2 validator: function (value) value >= 0 && value <= 2

View File

@@ -331,16 +331,7 @@ liberator.config = { //{{{
}, },
{ {
argCount: "+", argCount: "+",
completer: function (filter) completer: function (filter) liberator.completion.sidebar(filter)
{
var menu = document.getElementById("viewSidebarMenu");
var nodes = [];
for (let i = 0; i < menu.childNodes.length; i++)
nodes.push([menu.childNodes[i].label, ""]);
return [0, liberator.completion.filter(nodes, filter)];
}
}); });
liberator.commands.add(["winc[lose]", "wc[lose]"], liberator.commands.add(["winc[lose]", "wc[lose]"],