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

Make 'cpt' a stringlist. Add support for native autocomplete providers.

This commit is contained in:
Kris Maglione
2011-09-26 15:52:51 -04:00
parent 2ca292f55d
commit 45218f4141
15 changed files with 166 additions and 75 deletions

View File

@@ -706,9 +706,9 @@ var Bookmarks = Module("bookmarks", {
}); });
}; };
completion.addUrlCompleter("S", "Suggest engines", completion.searchEngineSuggest); completion.addUrlCompleter("suggestion", "Suggest engines", completion.searchEngineSuggest);
completion.addUrlCompleter("b", "Bookmarks", completion.bookmark); completion.addUrlCompleter("bookmark", "Bookmarks", completion.bookmark);
completion.addUrlCompleter("s", "Search engines and keyword URLs", completion.search); completion.addUrlCompleter("search", "Search engines and keyword URLs", completion.search);
} }
}); });

View File

@@ -1955,7 +1955,7 @@ var Buffer = Module("buffer", {
dactyl.assert(url, _("error.clipboardEmpty")); dactyl.assert(url, _("error.clipboardEmpty"));
let proto = /^([-\w]+):/.exec(url); 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.replace(/\s+/g, "");
return url; return url;
} }

View File

@@ -1108,7 +1108,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
// If it starts with a valid protocol, pass it through. // If it starts with a valid protocol, pass it through.
let proto = /^([-\w]+):/.exec(url); 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; return url;
// Check for a matching search keyword. // Check for a matching search keyword.

View File

@@ -312,7 +312,7 @@ var History = Module("history", {
context.generate = function () history.get(context.filter, this.maxItems, sort); context.generate = function () history.get(context.filter, this.maxItems, sort);
}; };
completion.addUrlCompleter("h", "History", completion.history); completion.addUrlCompleter("history", "History", completion.history);
}, },
mappings: function () { mappings: function () {
function bind() mappings.add.apply(mappings, [config.browserModes].concat(Array.slice(arguments))); function bind() mappings.add.apply(mappings, [config.browserModes].concat(Array.slice(arguments)));

View File

@@ -279,9 +279,9 @@ var KeyProcessor = Class("KeyProcessor", {
return KeyArgProcessor(this, map, true, "motion"); return KeyArgProcessor(this, map, true, "motion");
return this.execute(map, { return this.execute(map, {
keyEvents: this.keyEvents,
command: this.command, command: this.command,
count: this.count, count: this.count,
keyEvents: events.keyEvents,
keypressEvents: this.events keypressEvents: this.events
}); });
} }
@@ -313,7 +313,8 @@ var KeyArgProcessor = Class("KeyArgProcessor", KeyProcessor, {
let args = { let args = {
command: this.parent.command, command: this.parent.command,
count: this.count || this.parent.count, 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; args[this.argName] = this.command;

View File

@@ -37,6 +37,10 @@ autocmd.noMatching = No matching autocommands
autocmd.noGroup-1 = No such group or event: %S autocmd.noGroup-1 = No such group or event: %S
autocmd.cantExecuteAll = Can't execute autocommands for ALL events 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.noMatching-2 = No bookmarks matching tags %S and string %S
bookmark.noMatchingTags-1 = No bookmarks matching tags %S bookmark.noMatchingTags-1 = No bookmarks matching tags %S
bookmark.noMatchingString-1 = No bookmarks matching string %S bookmark.noMatchingString-1 = No bookmarks matching string %S

View File

@@ -510,22 +510,35 @@
<p>Items which are completed at the <ex>:open</ex> prompts. Available items:</p> <p>Items which are completed at the <ex>:open</ex> prompts. Available items:</p>
<dl dt="width: 6em;"> <dl dt="width: 6em;">
<dt>s</dt> <dd>Search engines and keyword URLs</dd> <dt>search</dt> <dd>Search engines and keyword URLs</dd>
<dt>f</dt> <dd>Local files</dd> <dt>file</dt> <dd>Local files</dd>
<dt>l</dt> <dd>&dactyl.host; location bar entries (bookmarks and history sorted in an intelligent way)</dd> <dt>location</dt> <dd>&dactyl.host; location bar entries (bookmarks and history sorted in an intelligent way)</dd>
<dt>b</dt> <dd>Bookmarks</dd> <dt>bookmark</dt> <dd>Bookmarks</dd>
<dt>h</dt> <dd>History</dd> <dt>history</dt> <dd>History</dd>
<dt>S</dt> <dd>Search engine suggestions</dd> <dt>suggest</dt> <dd>Search engine suggestions</dd>
</dl> </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> <p>
The order is important, such that <se opt="complete"><str delim="">bsf</str></se> will The order is important, such that <se opt="complete"><str delim="">bsf</str></se> will
list bookmarks followed by matching quick searches and then list bookmarks followed by matching quick searches and then
matching files. matching files.
</p> </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> <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. there are many items.
</warning> </warning>
</description> </description>

View File

@@ -10,7 +10,14 @@ defineModule("bookmarkcache", {
require: ["services", "storage", "util"] require: ["services", "storage", "util"]
}, this); }, 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 Bookmark = Struct("url", "title", "icon", "post", "keyword", "tags", "charset", "id");
var Keyword = Struct("keyword", "title", "icon", "url"); var Keyword = Struct("keyword", "title", "icon", "url");

View File

@@ -211,6 +211,16 @@ var CompletionContext = Class("CompletionContext", {
return this; 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 // Temporary
/** /**
* @property {Object} * @property {Object}
@@ -631,7 +641,17 @@ var CompletionContext = Class("CompletionContext", {
start = Math.max(0, start || 0); start = Math.max(0, start || 0);
end = Math.min(items.length, end != null ? end : items.length); end = Math.min(items.length, end != null ? end : items.length);
for (let i in util.range(start, end, step)) for (let i in util.range(start, end, step))
yield [i, cache[i] = cache[i] || util.xmlToDom(self.createRow(items[i]), doc)]; 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}&#xa0;</li>
<li highlight="CompDesc">{e}&#xa0;</li>
</div>, doc)];
}
}, },
/** /**
@@ -849,6 +869,7 @@ var Completion = Module("completion", {
Local: function (dactyl, modules, window) ({ Local: function (dactyl, modules, window) ({
urlCompleters: {}, urlCompleters: {},
get modules() modules,
get options() modules.options, get options() modules.options,
// FIXME // FIXME
@@ -920,8 +941,9 @@ var Completion = Module("completion", {
if (/^about:/.test(context.filter)) if (/^about:/.test(context.filter))
context.fork("about", 6, this, function (context) { context.fork("about", 6, this, function (context) {
context.generate = function () { context.generate = function () {
const PREFIX = "@mozilla.org/network/protocol/about;1?what="; return [[k.substr(services.ABOUT.length), ""]
return [[k.substr(PREFIX.length), ""] for (k in Cc) if (k.indexOf(PREFIX) == 0)]; 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) // Will, and should, throw an error if !(c in opts)
Array.forEach(complete, function (c) { 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); context.forkapply(c, 0, this, completer.completer, completer.args);
}, this); }, this);
}, },
@@ -941,6 +963,64 @@ var Completion = Module("completion", {
this.urlCompleters[opt] = completer; 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) { urls: function (context, tags) {
let compare = String.localeCompare; let compare = String.localeCompare;
let contains = String.indexOf; let contains = String.indexOf;
@@ -1053,8 +1133,32 @@ var Completion = Module("completion", {
options.add(["complete", "cpt"], options.add(["complete", "cpt"],
"Items which are completed at the :open prompts", "Items which are completed at the :open prompts",
"charlist", config.defaults.complete == null ? "slf" : config.defaults.complete, "stringlist", config.defaults.complete == null ? "slf" : config.defaults.complete,
{ get values() values(completion.urlCompleters).toArray() }); {
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"], options.add(["wildanchor", "wia"],
"Define which completion groups only match at the beginning of their text", "Define which completion groups only match at the beginning of their text",

View File

@@ -19,7 +19,7 @@ AboutHandler.prototype = {
classID: Components.ID("81495d80-89ee-4c36-a88d-ea7c4e5ac63f"), 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]), QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),

View File

@@ -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[ let match = util.regexp(<![CDATA[
^ ^
(?P<prefix> (?P<prefix>

View File

@@ -93,7 +93,7 @@ function ProtocolBase() {
}; };
} }
ProtocolBase.prototype = { ProtocolBase.prototype = {
get contractID() "@mozilla.org/network/protocol;1?name=" + this.scheme, get contractID() services.PROTOCOL + this.scheme,
get classDescription() this.scheme + " utility protocol", get classDescription() this.scheme + " utility protocol",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]), QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]),

View File

@@ -16,13 +16,16 @@ defineModule("services", {
* A lazily-instantiated XPCOM class and service cache. * A lazily-instantiated XPCOM class and service cache.
*/ */
var Services = Module("Services", { 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 () { init: function () {
this.services = {}; this.services = {};
this.add("annotation", "@mozilla.org/browser/annotation-service;1", "nsIAnnotationService"); this.add("annotation", "@mozilla.org/browser/annotation-service;1", "nsIAnnotationService");
this.add("appShell", "@mozilla.org/appshell/appShellService;1", "nsIAppShellService"); this.add("appShell", "@mozilla.org/appshell/appShellService;1", "nsIAppShellService");
this.add("appStartup", "@mozilla.org/toolkit/app-startup;1", "nsIAppStartup"); 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("bookmarks", "@mozilla.org/browser/nav-bookmarks-service;1", "nsINavBookmarksService");
this.add("bootstrap", "@dactyl.googlecode.com/base/bootstrap"); this.add("bootstrap", "@dactyl.googlecode.com/base/bootstrap");
this.add("browserSearch", "@mozilla.org/browser/search-service;1", "nsIBrowserSearchService"); 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("commandLineHandler", "@mozilla.org/commandlinehandler/general-startup;1?type=dactyl");
this.add("console", "@mozilla.org/consoleservice;1", "nsIConsoleService"); this.add("console", "@mozilla.org/consoleservice;1", "nsIConsoleService");
this.add("dactyl", "@dactyl.googlecode.com/extra/utils", "dactylIUtils"); 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("debugger", "@mozilla.org/js/jsd/debugger-service;1", "jsdIDebuggerService");
this.add("directory", "@mozilla.org/file/directory_service;1", "nsIProperties"); this.add("directory", "@mozilla.org/file/directory_service;1", "nsIProperties");
this.add("downloadManager", "@mozilla.org/download-manager;1", "nsIDownloadManager"); 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("externalApp", "@mozilla.org/uriloader/external-helper-app-service;1", "nsPIExternalAppLauncher")
this.add("externalProtocol", "@mozilla.org/uriloader/external-protocol-service;1", "nsIExternalProtocolService"); this.add("externalProtocol", "@mozilla.org/uriloader/external-protocol-service;1", "nsIExternalProtocolService");
this.add("favicon", "@mozilla.org/browser/favicon-service;1", "nsIFaviconService"); 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("focus", "@mozilla.org/focus-manager;1", "nsIFocusManager");
this.add("history", "@mozilla.org/browser/global-history;2", this.add("history", "@mozilla.org/browser/global-history;2",
["nsIBrowserHistory", "nsIGlobalHistory2", "nsINavHistoryService", "nsPIPlacesDatabase"]); ["nsIBrowserHistory", "nsIGlobalHistory2", "nsINavHistoryService", "nsPIPlacesDatabase"]);
@@ -57,7 +60,7 @@ var Services = Module("Services", {
this.add("pref", "@mozilla.org/preferences-service;1", ["nsIPrefBranch2", "nsIPrefService"]); this.add("pref", "@mozilla.org/preferences-service;1", ["nsIPrefBranch2", "nsIPrefService"]);
this.add("privateBrowsing", "@mozilla.org/privatebrowsing;1", "nsIPrivateBrowsingService"); this.add("privateBrowsing", "@mozilla.org/privatebrowsing;1", "nsIPrivateBrowsingService");
this.add("profile", "@mozilla.org/toolkit/profile-service;1", "nsIToolkitProfileService"); 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("runtime", "@mozilla.org/xre/runtime;1", ["nsIXULAppInfo", "nsIXULRuntime"]);
this.add("rdf", "@mozilla.org/rdf/rdf-service;1", "nsIRDFService"); this.add("rdf", "@mozilla.org/rdf/rdf-service;1", "nsIRDFService");
this.add("sessionStore", "@mozilla.org/browser/sessionstore;1", "nsISessionStore"); this.add("sessionStore", "@mozilla.org/browser/sessionstore;1", "nsISessionStore");

View File

@@ -168,6 +168,8 @@
- Boolean options no longer accept an argument. [b4] - Boolean options no longer accept an argument. [b4]
- 'cdpath' and 'runtimepath' no longer treat ",," - 'cdpath' and 'runtimepath' no longer treat ",,"
specially. Use "." instead. [b2] 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 - 'extendedhinttags' is now a [regexpmap] rather than a
string. [b2] string. [b2]
- 'guioptions' default value has changed. [b4][b7] - 'guioptions' default value has changed. [b4][b7]

View File

@@ -128,7 +128,7 @@ var Config = Module("config", ConfigBase, {
}, },
defaults: { defaults: {
complete: "slf", complete: "search,location,file",
guioptions: "bCrs", guioptions: "bCrs",
showtabline: "always", showtabline: "always",
titlestring: "Pentadactyl" titlestring: "Pentadactyl"
@@ -280,55 +280,12 @@ var Config = Module("config", ConfigBase, {
const { CompletionContext, bookmarkcache, completion } = modules; const { CompletionContext, bookmarkcache, completion } = modules;
const { document } = window; const { document } = window;
var searchRunning = null;
completion.location = function location(context) { completion.location = function location(context) {
if (!services.autoCompleteSearch) completion.autocomplete("history", context);
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;
context.title = ["Smart Completions"]; 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)", "Firefox location bar entries (bookmarks and history sorted in an intelligent way)",
completion.location); completion.location);