diff --git a/NEWS b/NEWS
index 445c2fa9..8adb7ce6 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@
* IMPORTANT: changed 'I' key to Ctrl-Q to also work in textboxes
* IMPORTANT: :bmarks! and :history! open the matching items now in a tab, instead
of bringing up the bookmarks/history window
+ * :set! now lets you change about:config prefs similar to :set
* new :command to add user defined commands
* new setCustomMode for plugin writers
* :au[tocmd] executes commands on events (only 'PageLoad' actually) on websites
diff --git a/TODO b/TODO
index dd585752..bf7805ad 100644
--- a/TODO
+++ b/TODO
@@ -23,7 +23,6 @@ FEATURES:
7 implement LocationList window, and get rid off/change PreviewWindow to be a real preview window being able to display html pages
7 [ctrl-o/i] to Go back to a Previous Position (done partly, however currenty does not use a per tab jumplist)
7 whereever possible: get rid of dialogs and ask console-like dialog questions or write error prompts directly on the webpage or with :echo()
-7 :set! should also set about:config options (with autocomplete)
7 [d could go to the last domain in the history stack. so if i browse from
google to another page and click 10 links there, [d would take me back to the google page
opera's fast forward does something like this
diff --git a/content/commands.js b/content/commands.js
index 2d25f5b5..bd555b6c 100644
--- a/content/commands.js
+++ b/content/commands.js
@@ -1909,7 +1909,56 @@ vimperator.Commands = function () //{{{
{
if (special)
{
- vimperator.echo("This WILL show all non-default about:config options");
+ var onlyNondefault = false;
+ if (!args)
+ {
+ args = "all";
+ onlyNondefault = true;
+ }
+ // 1 2 3 4 5
+ var matches = args.match(/^\s*?([a-zA-Z0-9\.\-_{}]+)([?&!])?\s*(([+-^]?)=(.*))?\s*$/);
+ var name = matches[1];
+ var reset = false;
+ var invertBoolean = false;
+
+ if (matches[2] == "&")
+ reset = true;
+ else if (matches[2] == "!")
+ invertBoolean = true;
+
+ if (name == "all" && reset)
+ vimperator.echoerr("You can't reset all the firefox options, it could make your browser unusable.");
+ else if (name == "all")
+ vimperator.options.listFirefoxPrefs(onlyNondefault, "");
+ else if (reset)
+ vimperator.options.resetFirefoxPref(name);
+ else if (invertBoolean)
+ vimperator.options.invertFirefoxBoolean(name);
+ else if (matches[3])
+ {
+ var value = matches[5];
+ switch (value)
+ {
+ case undefined:
+ value = "";
+ break;
+ case "true":
+ value = true;
+ break;
+ case "false":
+ value = false;
+ break;
+ default:
+ var valueInt = parseInt(value, 10);
+ if (!isNaN(valueInt))
+ value = valueInt;
+ }
+ vimperator.options.setFirefoxPref(name, value);
+ }
+ else
+ {
+ vimperator.options.listFirefoxPrefs(onlyNondefault, name);
+ }
return;
}
diff --git a/content/completion.js b/content/completion.js
index 116c5384..22438373 100644
--- a/content/completion.js
+++ b/content/completion.js
@@ -370,7 +370,34 @@ vimperator.Completion = function () //{{{
}
if (special)
- alert(":set! completion will complete about:config options");
+ {
+ var firefoxBranch = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefBranch);
+ var prefArray = firefoxBranch.getChildList("", {value: 0});
+ prefArray.sort();
+
+ if (filter.length > 0 && filter.lastIndexOf("=") == filter.length - 1)
+ {
+ for (var i = 0; i < prefArray.length; i++)
+ {
+ var name = prefArray[i];
+ if (name.match("^" + filter.substr(0, filter.length - 1) + "$" ))
+ {
+ var value = vimperator.options.getFirefoxPref(name);
+ return [filter.length + 1, [[value, ""]]];
+ }
+ }
+ return [0, []];
+ }
+
+ for (var i = 0; i < prefArray.length; i++)
+ optionCompletions.push([prefArray[i], vimperator.options.getFirefoxPref(prefArray[i])]);
+
+ if (!filter)
+ return [0, optionCompletions];
+
+ return [0, buildLongestCommonSubstring(optionCompletions, filter)];
+ }
if (!filter)
{
diff --git a/content/options.js b/content/options.js
index 37f2d063..417bf573 100644
--- a/content/options.js
+++ b/content/options.js
@@ -121,9 +121,10 @@ vimperator.Options = function () //{{{
////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
- var firefoxPrefs = Components.classes["@mozilla.org/preferences-service;1"]
+ var firefoxBranch = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
- var vimperatorPrefs = firefoxPrefs.getBranch("extensions.vimperator.");
+ var defaultBranch = firefoxBranch.getDefaultBranch("");
+ var vimperatorBranch = firefoxBranch.getBranch("extensions.vimperator.");
var options = [];
// save if we already changed a GUI related option, used for setInitialGUI
@@ -137,67 +138,67 @@ vimperator.Options = function () //{{{
throw StopIteration;
}
- function storePreference(name, value, vimperatorBranch)
+ function storePreference(name, value, branch)
{
- var branch;
+ if (!branch)
+ branch = firefoxBranch;
- if (vimperatorBranch)
- branch = vimperatorPrefs;
- else
- branch = firefoxPrefs;
+ var type = branch.getPrefType(name);
switch (typeof value)
{
case "string":
- branch.setCharPref(name, value);
+ if (type == branch.PREF_INVALID || type == branch.PREF_STRING)
+ branch.setCharPref(name, value);
+ else if (type == branch.PREF_INT)
+ vimperator.echoerr("E521: Number required after =: " + name + "=" + value);
+ else
+ vimperator.echoerr("E474: Invalid argument: " + name + "=" + value);
break;
case "number":
- branch.setIntPref(name, value);
+ if (type == branch.PREF_INVALID || type == branch.PREF_INT)
+ branch.setIntPref(name, value);
+ else
+ vimperator.echoerr("E474: Invalid argument: " + name + "=" + value);
break;
case "boolean":
- branch.setBoolPref(name, value);
+ if (type == branch.PREF_INVALID || type == branch.PREF_BOOL)
+ branch.setBoolPref(name, value);
+ else if (type == branch.PREF_INT)
+ vimperator.echoerr("E521: Number required after =: " + name + "=" + value);
+ else
+ vimperator.echoerr("E474: Invalid argument: " + name + "=" + value);
break;
default:
vimperator.echoerr("Unknown preference type: " + typeof value + " (" + name + "=" + value + ")");
}
}
- function loadPreference(name, forcedDefault, vimperatorBranch)
+ function loadPreference(name, forcedDefault, branch)
{
var defaultValue = null;
if (forcedDefault != null) // this argument sets defaults for non-user settable options (like comp_history)
defaultValue = forcedDefault;
- if (vimperatorBranch)
- {
- branch = vimperatorPrefs;
+ if (!branch)
+ branch = firefoxBranch;
- if (!forcedDefault) // this argument sets defaults for non-user settable options (like comp_history)
- {
- for (var i = 0; i < options.length; i++)
- {
- if (options[i].name == name) // only first name is searched
- {
- defaultValue = options[i].defaultValue;
- break;
- }
- }
- }
- }
- else
- {
- branch = firefoxPrefs;
- }
+ var type = branch.getPrefType(name);
try
{
- switch (typeof defaultValue)
+ switch (type)
{
- case "string":
- return branch.getCharPref(name);
- case "number":
+ case branch.PREF_STRING:
+ var value = branch.getComplexValue(name, Components.interfaces.nsISupportsString).data;
+ // Try in case it's a localized string (will throw an exception if not)
+ if (!branch.prefIsLocked(name) && !branch.prefHasUserValue(name) &&
+ /^chrome:\/\/.+\/locale\/.+\.properties/.test(value))
+ value = branch.getComplexValue(name, Components.interfaces.nsIPrefLocalizedString).data;
+ return value;
+ case branch.PREF_INT:
return branch.getIntPref(name);
- case "boolean":
+ case branch.PREF_BOOL:
return branch.getBoolPref(name);
default:
return defaultValue;
@@ -369,6 +370,46 @@ vimperator.Options = function () //{{{
vimperator.commandline.echo(list, vimperator.commandline.HL_NORMAL, vimperator.commandline.FORCE_MULTILINE);
},
+ listFirefoxPrefs: function (onlyNondefault, filter)
+ {
+ if (!filter)
+ filter = "";
+ var prefArray = firefoxBranch.getChildList("", {value: 0});
+ prefArray.sort();
+ var list = ":" + vimperator.util.escapeHTML(vimperator.commandline.getCommand()) + "
" +
+ "
| --- Firefox Options --- |
|---|
| " + name + "=" + value + " (" + defaultValue + ") |
| " + name + "=" + value + " |