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()) + "
" + + ""; + var name, value; + + for (var i = 0; i < prefArray.length; i++) + { + var userValue = firefoxBranch.prefHasUserValue(prefArray[i]); + if ((!onlyNondefault || userValue) && prefArray[i].indexOf(filter) >= 0) + { + name = prefArray[i]; + value = this.getFirefoxPref(name); + if (typeof value == "string") + value = value.substr(0,100).replace(/\n/g, " "); + + value = vimperator.util.colorize(value, false); + defaultValue = loadPreference(name, null, defaultBranch); + + if (defaultValue == null) + defaultValue = "new preference"; + else + defaultValue = "default: " + defaultValue; + + if (userValue) + { + list += ""; + } + else + list += ""; + } + } + list += "
--- Firefox Options ---
" + name + "=" + value + " (" + defaultValue + ")
" + name + "=" + value + "
"; + vimperator.commandline.echo(list, vimperator.commandline.HL_NORMAL, vimperator.commandline.FORCE_MULTILINE); + }, + // this hack is only needed, because we need to do asynchronous loading of the .vimperatorrc setInitialGUI: function () { @@ -384,12 +425,12 @@ vimperator.Options = function () //{{{ // be better placed in the 'core' vimperator namespace somewhere? setPref: function (name, value) { - return storePreference(name, value, true); + return storePreference(name, value, vimperatorBranch); }, getPref: function (name, forcedDefault) { - return loadPreference(name, forcedDefault, true); + return loadPreference(name, forcedDefault, vimperatorBranch); }, setFirefoxPref: function (name, value) @@ -400,6 +441,18 @@ vimperator.Options = function () //{{{ getFirefoxPref: function (name, forcedDefault) { return loadPreference(name, forcedDefault); + }, + + resetFirefoxPref: function (name) + { + return firefoxBranch.clearUserPref(name); + }, + invertFirefoxBoolean: function (name) + { + if (firefoxBranch.getPrefType(name) == firefoxBranch.PREF_BOOL) + this.setFirefoxPref(name, !this.getFirefoxPref(name)); + else + vimperator.echoerr("E488: Trailing characters: " + name + "!"); } };