mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-22 02:17:59 +01:00
Make 'cpt' a stringlist. Add support for native autocomplete providers.
This commit is contained in:
@@ -706,9 +706,9 @@ var Bookmarks = Module("bookmarks", {
|
||||
});
|
||||
};
|
||||
|
||||
completion.addUrlCompleter("S", "Suggest engines", completion.searchEngineSuggest);
|
||||
completion.addUrlCompleter("b", "Bookmarks", completion.bookmark);
|
||||
completion.addUrlCompleter("s", "Search engines and keyword URLs", completion.search);
|
||||
completion.addUrlCompleter("suggestion", "Suggest engines", completion.searchEngineSuggest);
|
||||
completion.addUrlCompleter("bookmark", "Bookmarks", completion.bookmark);
|
||||
completion.addUrlCompleter("search", "Search engines and keyword URLs", completion.search);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1955,7 +1955,7 @@ var Buffer = Module("buffer", {
|
||||
dactyl.assert(url, _("error.clipboardEmpty"));
|
||||
|
||||
let proto = /^([-\w]+):/.exec(url);
|
||||
if (proto && "@mozilla.org/network/protocol;1?name=" + proto[1] in Cc && !RegExp(options["urlseparator"]).test(url))
|
||||
if (proto && services.PROTOCOL + proto[1] in Cc && !RegExp(options["urlseparator"]).test(url))
|
||||
return url.replace(/\s+/g, "");
|
||||
return url;
|
||||
}
|
||||
|
||||
@@ -1108,7 +1108,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
||||
|
||||
// If it starts with a valid protocol, pass it through.
|
||||
let proto = /^([-\w]+):/.exec(url);
|
||||
if (proto && "@mozilla.org/network/protocol;1?name=" + proto[1] in Cc)
|
||||
if (proto && services.PROTOCOL + proto[1] in Cc)
|
||||
return url;
|
||||
|
||||
// Check for a matching search keyword.
|
||||
|
||||
@@ -312,7 +312,7 @@ var History = Module("history", {
|
||||
context.generate = function () history.get(context.filter, this.maxItems, sort);
|
||||
};
|
||||
|
||||
completion.addUrlCompleter("h", "History", completion.history);
|
||||
completion.addUrlCompleter("history", "History", completion.history);
|
||||
},
|
||||
mappings: function () {
|
||||
function bind() mappings.add.apply(mappings, [config.browserModes].concat(Array.slice(arguments)));
|
||||
|
||||
@@ -279,9 +279,9 @@ var KeyProcessor = Class("KeyProcessor", {
|
||||
return KeyArgProcessor(this, map, true, "motion");
|
||||
|
||||
return this.execute(map, {
|
||||
keyEvents: this.keyEvents,
|
||||
command: this.command,
|
||||
count: this.count,
|
||||
keyEvents: events.keyEvents,
|
||||
keypressEvents: this.events
|
||||
});
|
||||
}
|
||||
@@ -313,7 +313,8 @@ var KeyArgProcessor = Class("KeyArgProcessor", KeyProcessor, {
|
||||
let args = {
|
||||
command: this.parent.command,
|
||||
count: this.count || this.parent.count,
|
||||
events: this.parent.events.concat(this.events)
|
||||
keyEvents: events.keyEvents,
|
||||
keypressEvents: this.parent.events.concat(this.events)
|
||||
};
|
||||
args[this.argName] = this.command;
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@ autocmd.noMatching = No matching autocommands
|
||||
autocmd.noGroup-1 = No such group or event: %S
|
||||
autocmd.cantExecuteAll = Can't execute autocommands for ALL events
|
||||
|
||||
autocomplete.description-1 = Native '%S' autocompletions
|
||||
autocomplete.noSuchProvider-1 = No such autocomplete provider '%S'
|
||||
autocomplete.title-1 = '%S'
|
||||
|
||||
bookmark.noMatching-2 = No bookmarks matching tags %S and string %S
|
||||
bookmark.noMatchingTags-1 = No bookmarks matching tags %S
|
||||
bookmark.noMatchingString-1 = No bookmarks matching string %S
|
||||
|
||||
@@ -510,22 +510,35 @@
|
||||
<p>Items which are completed at the <ex>:open</ex> prompts. Available items:</p>
|
||||
|
||||
<dl dt="width: 6em;">
|
||||
<dt>s</dt> <dd>Search engines and keyword URLs</dd>
|
||||
<dt>f</dt> <dd>Local files</dd>
|
||||
<dt>l</dt> <dd>&dactyl.host; location bar entries (bookmarks and history sorted in an intelligent way)</dd>
|
||||
<dt>b</dt> <dd>Bookmarks</dd>
|
||||
<dt>h</dt> <dd>History</dd>
|
||||
<dt>S</dt> <dd>Search engine suggestions</dd>
|
||||
<dt>search</dt> <dd>Search engines and keyword URLs</dd>
|
||||
<dt>file</dt> <dd>Local files</dd>
|
||||
<dt>location</dt> <dd>&dactyl.host; location bar entries (bookmarks and history sorted in an intelligent way)</dd>
|
||||
<dt>bookmark</dt> <dd>Bookmarks</dd>
|
||||
<dt>history</dt> <dd>History</dd>
|
||||
<dt>suggest</dt> <dd>Search engine suggestions</dd>
|
||||
</dl>
|
||||
|
||||
<p>
|
||||
Additionally, native search providers can be added by prefixing
|
||||
their names with the string <str delim="'">native:</str>. These
|
||||
providers are often added by other add-ons and are occasionally
|
||||
useful.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The order is important, such that <se opt="complete"><str delim="">bsf</str></se> will
|
||||
list bookmarks followed by matching quick searches and then
|
||||
matching files.
|
||||
</p>
|
||||
|
||||
<note>
|
||||
For backward compatibility, this option currently accepts a single
|
||||
entry containing single-letter names for completers. This usage
|
||||
is deprecated and will be removed in the future.
|
||||
</note>
|
||||
|
||||
<warning>
|
||||
Using <em>b</em> and <em>h</em> can make completion very slow if
|
||||
Using <em>bookmark</em> and <em>history</em> can make completion very slow if
|
||||
there are many items.
|
||||
</warning>
|
||||
</description>
|
||||
|
||||
@@ -10,7 +10,14 @@ defineModule("bookmarkcache", {
|
||||
require: ["services", "storage", "util"]
|
||||
}, this);
|
||||
|
||||
function newURI(url, charset, base) services.io.newURI(url, charset, base);
|
||||
function newURI(url, charset, base) {
|
||||
try {
|
||||
return services.io.newURI(url, charset, base);
|
||||
}
|
||||
catch (e) {
|
||||
throw Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
var Bookmark = Struct("url", "title", "icon", "post", "keyword", "tags", "charset", "id");
|
||||
var Keyword = Struct("keyword", "title", "icon", "url");
|
||||
|
||||
@@ -211,6 +211,16 @@ var CompletionContext = Class("CompletionContext", {
|
||||
return this;
|
||||
},
|
||||
|
||||
__title: Class.Memoize(function () this._title.map(function (s)
|
||||
typeof s == "string" ? messages.get("completion.title." + s, s)
|
||||
: s)),
|
||||
|
||||
set title(val) {
|
||||
delete this.__title;
|
||||
return this._title = val;
|
||||
},
|
||||
get title() this.__title,
|
||||
|
||||
// Temporary
|
||||
/**
|
||||
* @property {Object}
|
||||
@@ -631,7 +641,17 @@ var CompletionContext = Class("CompletionContext", {
|
||||
start = Math.max(0, start || 0);
|
||||
end = Math.min(items.length, end != null ? end : items.length);
|
||||
for (let i in util.range(start, end, step))
|
||||
try {
|
||||
yield [i, cache[i] = cache[i] || util.xmlToDom(self.createRow(items[i]), doc)];
|
||||
}
|
||||
catch (e) {
|
||||
util.reportError(e);
|
||||
yield [i, cache[i] = cache[i] || util.xmlToDom(
|
||||
<div highlight={highlightGroup || "CompItem"} style="white-space: nowrap">
|
||||
<li highlight="CompResult">{items[i].text} </li>
|
||||
<li highlight="CompDesc">{e} </li>
|
||||
</div>, doc)];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -849,6 +869,7 @@ var Completion = Module("completion", {
|
||||
Local: function (dactyl, modules, window) ({
|
||||
urlCompleters: {},
|
||||
|
||||
get modules() modules,
|
||||
get options() modules.options,
|
||||
|
||||
// FIXME
|
||||
@@ -920,8 +941,9 @@ var Completion = Module("completion", {
|
||||
if (/^about:/.test(context.filter))
|
||||
context.fork("about", 6, this, function (context) {
|
||||
context.generate = function () {
|
||||
const PREFIX = "@mozilla.org/network/protocol/about;1?what=";
|
||||
return [[k.substr(PREFIX.length), ""] for (k in Cc) if (k.indexOf(PREFIX) == 0)];
|
||||
return [[k.substr(services.ABOUT.length), ""]
|
||||
for (k in Cc)
|
||||
if (k.indexOf(services.ABOUT) == 0)];
|
||||
};
|
||||
});
|
||||
|
||||
@@ -930,7 +952,7 @@ var Completion = Module("completion", {
|
||||
|
||||
// Will, and should, throw an error if !(c in opts)
|
||||
Array.forEach(complete, function (c) {
|
||||
let completer = this.urlCompleters[c];
|
||||
let completer = this.urlCompleters[c] || { args: [], completer: this.autocomplete(c.replace(/^native:/, "")) };
|
||||
context.forkapply(c, 0, this, completer.completer, completer.args);
|
||||
}, this);
|
||||
},
|
||||
@@ -941,6 +963,64 @@ var Completion = Module("completion", {
|
||||
this.urlCompleters[opt] = completer;
|
||||
},
|
||||
|
||||
autocomplete: curry(function autocomplete(provider, context) {
|
||||
let running = context.getCache("autocomplete-search-running", Object);
|
||||
|
||||
let name = "autocomplete:" + provider;
|
||||
if (!services.has(name))
|
||||
services.add(name, services.AUTOCOMPLETE + provider, "nsIAutoCompleteSearch");
|
||||
let service = services[name];
|
||||
|
||||
util.assert(service, _("autocomplete.noSuchProvider", provider), false);
|
||||
|
||||
if (running[provider]) {
|
||||
this.completions = this.completions;
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
context.anchored = false;
|
||||
context.compare = CompletionContext.Sort.unsorted;
|
||||
context.filterFunc = null;
|
||||
|
||||
let words = context.filter.toLowerCase().split(/\s+/g);
|
||||
context.hasItems = true;
|
||||
context.completions = context.completions.filter(function ({ url, title })
|
||||
words.every(function (w) (url + " " + title).toLowerCase().indexOf(w) >= 0))
|
||||
context.incomplete = true;
|
||||
|
||||
context.format = this.modules.bookmarks.format;
|
||||
context.keys.extra = function (item) {
|
||||
try {
|
||||
return bookmarkcache.get(item.url).extra;
|
||||
}
|
||||
catch (e) {}
|
||||
return null;
|
||||
};
|
||||
context.title = [_("autocomplete.title", provider)];
|
||||
|
||||
context.cancel = function () {
|
||||
this.incomplete = false;
|
||||
if (running[provider])
|
||||
service.stopSearch();
|
||||
running[provider] = false;
|
||||
};
|
||||
|
||||
service.startSearch(context.filter, "", context.result, {
|
||||
onSearchResult: function onSearchResult(search, result) {
|
||||
if (result.searchResult <= result.RESULT_SUCCESS)
|
||||
running[provider] = null;
|
||||
|
||||
context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
|
||||
context.completions = [
|
||||
{ url: result.getValueAt(i), title: result.getCommentAt(i), icon: result.getImageAt(i) }
|
||||
for (i in util.range(0, result.matchCount))
|
||||
];
|
||||
},
|
||||
get onUpdateSearchResult() this.onSearchResult
|
||||
});
|
||||
running[provider] = true;
|
||||
}),
|
||||
|
||||
urls: function (context, tags) {
|
||||
let compare = String.localeCompare;
|
||||
let contains = String.indexOf;
|
||||
@@ -1053,8 +1133,32 @@ var Completion = Module("completion", {
|
||||
|
||||
options.add(["complete", "cpt"],
|
||||
"Items which are completed at the :open prompts",
|
||||
"charlist", config.defaults.complete == null ? "slf" : config.defaults.complete,
|
||||
{ get values() values(completion.urlCompleters).toArray() });
|
||||
"stringlist", config.defaults.complete == null ? "slf" : config.defaults.complete,
|
||||
{
|
||||
valueMap: {
|
||||
S: "suggestion",
|
||||
b: "bookmark",
|
||||
f: "file",
|
||||
h: "history",
|
||||
l: "location",
|
||||
s: "search"
|
||||
},
|
||||
|
||||
get values() values(completion.urlCompleters).toArray()
|
||||
.concat([let (name = k.substr(services.AUTOCOMPLETE.length))
|
||||
["native:" + name, _("autocomplete.description", name)]
|
||||
for (k in Cc)
|
||||
if (k.indexOf(services.AUTOCOMPLETE) == 0)]),
|
||||
|
||||
setter: function setter(values) {
|
||||
if (values.length == 1 && !Set.has(values[0], this.values)
|
||||
&& Array.every(values[0], Set.has(this.valueMap)))
|
||||
return Array.map(values[0], function (v) this[v], this.valueMap);
|
||||
return values;
|
||||
},
|
||||
|
||||
validator: function validator(values) validator.supercall(this, this.setter(values))
|
||||
});
|
||||
|
||||
options.add(["wildanchor", "wia"],
|
||||
"Define which completion groups only match at the beginning of their text",
|
||||
|
||||
@@ -19,7 +19,7 @@ AboutHandler.prototype = {
|
||||
|
||||
classID: Components.ID("81495d80-89ee-4c36-a88d-ea7c4e5ac63f"),
|
||||
|
||||
get contractID() "@mozilla.org/network/protocol/about;1?what=" + config.name,
|
||||
get contractID() services.ABOUT + config.name,
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
|
||||
|
||||
|
||||
@@ -976,7 +976,7 @@ unlet s:cpo_save
|
||||
};
|
||||
};
|
||||
|
||||
completion.addUrlCompleter("f", "Local files", function (context, full) {
|
||||
completion.addUrlCompleter("file", "Local files", function (context, full) {
|
||||
let match = util.regexp(<![CDATA[
|
||||
^
|
||||
(?P<prefix>
|
||||
|
||||
@@ -93,7 +93,7 @@ function ProtocolBase() {
|
||||
};
|
||||
}
|
||||
ProtocolBase.prototype = {
|
||||
get contractID() "@mozilla.org/network/protocol;1?name=" + this.scheme,
|
||||
get contractID() services.PROTOCOL + this.scheme,
|
||||
get classDescription() this.scheme + " utility protocol",
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]),
|
||||
|
||||
|
||||
@@ -16,13 +16,16 @@ defineModule("services", {
|
||||
* A lazily-instantiated XPCOM class and service cache.
|
||||
*/
|
||||
var Services = Module("Services", {
|
||||
ABOUT: "@mozilla.org/network/protocol/about;1?what=",
|
||||
AUTOCOMPLETE: "@mozilla.org/autocomplete/search;1?name=",
|
||||
PROTOCOL: "@mozilla.org/network/protocol;1?name=",
|
||||
|
||||
init: function () {
|
||||
this.services = {};
|
||||
|
||||
this.add("annotation", "@mozilla.org/browser/annotation-service;1", "nsIAnnotationService");
|
||||
this.add("appShell", "@mozilla.org/appshell/appShellService;1", "nsIAppShellService");
|
||||
this.add("appStartup", "@mozilla.org/toolkit/app-startup;1", "nsIAppStartup");
|
||||
this.add("autoCompleteSearch", "@mozilla.org/autocomplete/search;1?name=history", "nsIAutoCompleteSearch");
|
||||
this.add("bookmarks", "@mozilla.org/browser/nav-bookmarks-service;1", "nsINavBookmarksService");
|
||||
this.add("bootstrap", "@dactyl.googlecode.com/base/bootstrap");
|
||||
this.add("browserSearch", "@mozilla.org/browser/search-service;1", "nsIBrowserSearchService");
|
||||
@@ -34,7 +37,7 @@ var Services = Module("Services", {
|
||||
this.add("commandLineHandler", "@mozilla.org/commandlinehandler/general-startup;1?type=dactyl");
|
||||
this.add("console", "@mozilla.org/consoleservice;1", "nsIConsoleService");
|
||||
this.add("dactyl", "@dactyl.googlecode.com/extra/utils", "dactylIUtils");
|
||||
this.add("dactyl:", "@mozilla.org/network/protocol;1?name=dactyl");
|
||||
this.add("dactyl:", this.PROTOCOL + "dactyl");
|
||||
this.add("debugger", "@mozilla.org/js/jsd/debugger-service;1", "jsdIDebuggerService");
|
||||
this.add("directory", "@mozilla.org/file/directory_service;1", "nsIProperties");
|
||||
this.add("downloadManager", "@mozilla.org/download-manager;1", "nsIDownloadManager");
|
||||
@@ -43,7 +46,7 @@ var Services = Module("Services", {
|
||||
this.add("externalApp", "@mozilla.org/uriloader/external-helper-app-service;1", "nsPIExternalAppLauncher")
|
||||
this.add("externalProtocol", "@mozilla.org/uriloader/external-protocol-service;1", "nsIExternalProtocolService");
|
||||
this.add("favicon", "@mozilla.org/browser/favicon-service;1", "nsIFaviconService");
|
||||
this.add("file:", "@mozilla.org/network/protocol;1?name=file", "nsIFileProtocolHandler");
|
||||
this.add("file:", this.PROTOCOL + "file", "nsIFileProtocolHandler");
|
||||
this.add("focus", "@mozilla.org/focus-manager;1", "nsIFocusManager");
|
||||
this.add("history", "@mozilla.org/browser/global-history;2",
|
||||
["nsIBrowserHistory", "nsIGlobalHistory2", "nsINavHistoryService", "nsPIPlacesDatabase"]);
|
||||
@@ -57,7 +60,7 @@ var Services = Module("Services", {
|
||||
this.add("pref", "@mozilla.org/preferences-service;1", ["nsIPrefBranch2", "nsIPrefService"]);
|
||||
this.add("privateBrowsing", "@mozilla.org/privatebrowsing;1", "nsIPrivateBrowsingService");
|
||||
this.add("profile", "@mozilla.org/toolkit/profile-service;1", "nsIToolkitProfileService");
|
||||
this.add("resource:", "@mozilla.org/network/protocol;1?name=resource", ["nsIProtocolHandler", "nsIResProtocolHandler"]);
|
||||
this.add("resource:", this.PROTOCOL + "resource", ["nsIProtocolHandler", "nsIResProtocolHandler"]);
|
||||
this.add("runtime", "@mozilla.org/xre/runtime;1", ["nsIXULAppInfo", "nsIXULRuntime"]);
|
||||
this.add("rdf", "@mozilla.org/rdf/rdf-service;1", "nsIRDFService");
|
||||
this.add("sessionStore", "@mozilla.org/browser/sessionstore;1", "nsISessionStore");
|
||||
|
||||
@@ -168,6 +168,8 @@
|
||||
- Boolean options no longer accept an argument. [b4]
|
||||
- 'cdpath' and 'runtimepath' no longer treat ",,"
|
||||
specially. Use "." instead. [b2]
|
||||
- 'complete' is now a [stringlist] rather than a [charlist]
|
||||
and supports native autocomplete providers. [b8]
|
||||
- 'extendedhinttags' is now a [regexpmap] rather than a
|
||||
string. [b2]
|
||||
- 'guioptions' default value has changed. [b4][b7]
|
||||
|
||||
@@ -128,7 +128,7 @@ var Config = Module("config", ConfigBase, {
|
||||
},
|
||||
|
||||
defaults: {
|
||||
complete: "slf",
|
||||
complete: "search,location,file",
|
||||
guioptions: "bCrs",
|
||||
showtabline: "always",
|
||||
titlestring: "Pentadactyl"
|
||||
@@ -280,55 +280,12 @@ var Config = Module("config", ConfigBase, {
|
||||
const { CompletionContext, bookmarkcache, completion } = modules;
|
||||
const { document } = window;
|
||||
|
||||
var searchRunning = null;
|
||||
completion.location = function location(context) {
|
||||
if (!services.autoCompleteSearch)
|
||||
return;
|
||||
|
||||
if (searchRunning) {
|
||||
searchRunning.completions = searchRunning.completions;
|
||||
searchRunning.cancel();
|
||||
}
|
||||
|
||||
context.anchored = false;
|
||||
context.compare = CompletionContext.Sort.unsorted;
|
||||
context.filterFunc = null;
|
||||
|
||||
let words = context.filter.toLowerCase().split(/\s+/g);
|
||||
context.hasItems = true;
|
||||
context.completions = context.completions.filter(function ({ url, title })
|
||||
words.every(function (w) (url + " " + title).toLowerCase().indexOf(w) >= 0))
|
||||
context.incomplete = true;
|
||||
|
||||
context.format = modules.bookmarks.format;
|
||||
context.keys.extra = function (item) (bookmarkcache.get(item.url) || {}).extra;
|
||||
completion.autocomplete("history", context);
|
||||
context.title = ["Smart Completions"];
|
||||
|
||||
context.cancel = function () {
|
||||
this.incomplete = false;
|
||||
if (searchRunning === this) {
|
||||
services.autoCompleteSearch.stopSearch();
|
||||
searchRunning = null;
|
||||
}
|
||||
};
|
||||
|
||||
services.autoCompleteSearch.startSearch(context.filter, "", context.result, {
|
||||
onSearchResult: function onSearchResult(search, result) {
|
||||
if (result.searchResult <= result.RESULT_SUCCESS)
|
||||
searchRunning = null;
|
||||
|
||||
context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
|
||||
context.completions = [
|
||||
{ url: result.getValueAt(i), title: result.getCommentAt(i), icon: result.getImageAt(i) }
|
||||
for (i in util.range(0, result.matchCount))
|
||||
];
|
||||
},
|
||||
get onUpdateSearchResult() this.onSearchResult
|
||||
});
|
||||
searchRunning = context;
|
||||
};
|
||||
|
||||
completion.addUrlCompleter("l",
|
||||
completion.addUrlCompleter("location",
|
||||
"Firefox location bar entries (bookmarks and history sorted in an intelligent way)",
|
||||
completion.location);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user