diff --git a/common/content/commands.js b/common/content/commands.js index 420b78f8..26b5d949 100644 --- a/common/content/commands.js +++ b/common/content/commands.js @@ -41,14 +41,15 @@ the terms of any one of the MPL, the GPL or the LGPL. * @param {function} action The action invoked by this command when executed. * @param {Object} extraInfo An optional extra configuration hash. The * following properties are supported. - * argCount - See (@link Command#argCount) - * bang - See (@link Command#bang) - * completer - See (@link Command#completer) - * count - See (@link Command#count) - * heredoc - See (@link Command#heredoc) - * literal - See (@link Command#literal) - * options - See (@link Command#options) - * serial - See (@link Command#serial) + * argCount - see {@link Command#argCount} + * bang - see {@link Command#bang} + * completer - see {@link Command#completer} + * count - see {@link Command#count} + * heredoc - see {@link Command#heredoc} + * literal - see {@link Command#literal} + * options - see {@link Command#options} + * serial - see {@link Command#serial} + * @optional * @private */ function Command(specs, description, action, extraInfo) //{{{ @@ -91,64 +92,84 @@ function Command(specs, description, action, extraInfo) //{{{ }; let expandedSpecs = parseSpecs(specs); - /** @property {string[]} All of this command's name spacs. e.g., "com[mand]" */ + /** + * @property {string[]} All of this command's name specs. e.g., "com[mand]" + */ this.specs = specs; /** @property {string[]} All of this command's short names, e.g., "com" */ this.shortNames = expandedSpecs.shortNames; - /** @property {string[]} All of this command's long names, e.g., "command" */ - this.longNames = expandedSpecs.longNames; + /** + * @property {string[]} All of this command's long names, e.g., "command" + */ + this.longNames = expandedSpecs.longNames; /** @property {string} The command's canonical name. */ - this.name = this.longNames[0]; + this.name = this.longNames[0]; /** @property {string[]} All of this command's long and short names. */ - this.names = expandedSpecs.names; // return all command name aliases + this.names = expandedSpecs.names; // return all command name aliases /** @property {string} This command's description, as shown in :exusage */ this.description = description || ""; - /** @property {function (Args)} The function called to execute this command. */ - this.action = action; - /** @property {string} This command's argument count spec. @see Commands#parseArguments */ - this.argCount = extraInfo.argCount || 0; - /** @property {function (CompletionContext, Args)} This command's completer. @see CompletionContext */ - this.completer = extraInfo.completer || null; + /** + * @property {function (Args)} The function called to execute this command. + */ + this.action = action; + /** + * @property {string} This command's argument count spec. + * @see Commands#parseArguments + */ + this.argCount = extraInfo.argCount || 0; + /** + * @property {function (CompletionContext, Args)} This command's completer. + * @see CompletionContext + */ + this.completer = extraInfo.completer || null; /** @property {boolean} Whether this command accepts a here document. */ - this.hereDoc = extraInfo.hereDoc || false; - /** @property {Array} The options this command takes. @see Commands@parseArguments */ - this.options = extraInfo.options || []; - /** @property {boolean} Whether this command may be called with a bang, e.g., :com! */ - this.bang = extraInfo.bang || false; - /** @property {boolean} Whether this command may be called with a count, e.g., :12bdel */ - this.count = extraInfo.count || false; + this.hereDoc = extraInfo.hereDoc || false; /** - * @property {boolean} At what index this command's literal - * arguments begin. For instance, with a value of 2, all arguments - * starting with the third are parsed as a single string, with all - * quoting characters passed literally. This is especially useful for - * commands which take key mappings or Ex command lines as - * arguments. + * @property {Array} The options this command takes. + * @see Commands@parseArguments */ - this.literal = extraInfo.literal == null ? null : extraInfo.literal; + this.options = extraInfo.options || []; /** - * @property {function} Should return an array of Objects - * suitable to be passed to {@link Commands#commandToString}, one - * for each past invocation which should be restored on subsequent - * @liberator startups. + * @property {boolean} Whether this command may be called with a bang, + * e.g., :com! */ - this.serial = extraInfo.serial; + this.bang = extraInfo.bang || false; + /** + * @property {boolean} Whether this command may be called with a count, + * e.g., :12bdel + */ + this.count = extraInfo.count || false; + /** + * @property {boolean} At what index this command's literal arguments + * begin. For instance, with a value of 2, all arguments starting with + * the third are parsed as a single string, with all quoting characters + * passed literally. This is especially useful for commands which take + * key mappings or Ex command lines as arguments. + */ + this.literal = extraInfo.literal == null ? null : extraInfo.literal; + /** + * @property {function} Should return an array of Objects suitable + * to be passed to {@link Commands#commandToString}, one for each past + * invocation which should be restored on subsequent @liberator + * startups. + */ + this.serial = extraInfo.serial; /** - * @property {boolean} Specifies whether this is a user command. - * User commands may be created by plugins, or directly by users, - * and, unlike basic commands, may be overwritten. Users and - * plugin authors should create only user commands. + * @property {boolean} Specifies whether this is a user command. User + * commands may be created by plugins, or directly by users, and, + * unlike basic commands, may be overwritten. Users and plugin authors + * should create only user commands. */ - this.isUserCommand = extraInfo.isUserCommand || false; + this.isUserCommand = extraInfo.isUserCommand || false; /** - * @property {string} For commands defined via :command, contains - * the Ex command line to be executed upon invocation. + * @property {string} For commands defined via :command, contains the Ex + * command line to be executed upon invocation. */ this.replacementText = extraInfo.replacementText || null; -}; +} Command.prototype = { @@ -286,6 +307,66 @@ function Commands() //{{{ ArgType("list", function (arg) arg && arg.split(/\s*,\s*/)) ]; + // returns [count, parsed_argument] + function parseArg(str) + { + let arg = ""; + let quote = null; + let len = str.length; + + while (str.length && !/^\s/.test(str)) + { + let res; + + switch (QUOTE_STYLE) + { + case "vim-sucks": + if (res = str.match = str.match(/^()((?:[^\\\s]|\\.)+)((?:\\$)?)/)) + arg += res[2].replace(/\\(.)/g, "$1"); + break; + + case "vimperator": + if (res = str.match(/^()((?:[^\\\s"']|\\.)+)((?:\\$)?)/)) + arg += res[2].replace(/\\(.)/g, "$1"); + else if (res = str.match(/^(")((?:[^\\"]|\\.)*)("?)/)) + arg += eval(res[0] + (res[3] ? "" : '"')); + else if (res = str.match(/^(')((?:[^\\']|\\.)*)('?)/)) + arg += res[2].replace(/\\(.)/g, function (n0, n1) /[\\']/.test(n1) ? n1 : n0); + break; + + case "rc-ish": + if (res = str.match = str.match(/^()((?:[^\\\s"']|\\.)+)((?:\\$)?)/)) + arg += res[2].replace(/\\(.)/g, "$1"); + else if (res = str.match(/^(")((?:[^\\"]|\\.)*)("?)/)) + arg += eval(res[0] + (res[3] ? "" : '"')); + else if (res = str.match(/^(')((?:[^']|'')*)('?)/)) + arg += res[2].replace("''", "'", "g"); + break; + + case "pythonesque": + if (res = str.match = str.match(/^()((?:[^\\\s"']|\\.)+)((?:\\$)?)/)) + arg += res[2].replace(/\\(.)/g, "$1"); + else if (res = str.match(/^(""")((?:.?.?[^"])*)((?:""")?)/)) + arg += res[2]; + else if (res = str.match(/^(")((?:[^\\"]|\\.)*)("?)/)) + arg += eval(res[0] + (res[3] ? "" : '"')); + else if (res = str.match(/^(')((?:[^\\']|\\.)*)('?)/)) + arg += res[2].replace(/\\(.)/g, function (n0, n1) /[\\']/.test(n1) ? n1 : n0); + break; + } + + if (!res) + break; + if (!res[3]) + quote = res[1]; + if (!res[1]) + quote = res[3]; + str = str.substr(res[0].length); + } + + return [len - str.length, arg, quote]; + } + function addCommand(command, isUserCommand, replace) { if (!command) // XXX @@ -321,29 +402,93 @@ function Commands() //{{{ const self = { // FIXME: remove later, when our option handler is better - OPTION_ANY: 0, // can be given no argument or an argument of any type, - // caller is responsible for parsing the return value - OPTION_NOARG: 1, - OPTION_BOOL: 2, + /** + * @property The option argument is unspecified. Any argument is + * accepted and caller is responsible for parsing the return value. + * @final + */ + OPTION_ANY: 0, + + /** + * @property The option doesn't accept an argument. + * @final + */ + OPTION_NOARG: 1, + /** + * @property The option accepts a boolean argument. + * @final + */ + OPTION_BOOL: 2, + /** + * @property The option accepts a string argument. + * @final + */ OPTION_STRING: 3, - OPTION_INT: 4, - OPTION_FLOAT: 5, - OPTION_LIST: 6, + /** + * @property The option accepts an integer argument. + * @final + */ + OPTION_INT: 4, + /** + * @property The option accepts a float argument. + * @final + */ + OPTION_FLOAT: 5, + /** + * @property The option accepts a string list argument. E.g. "foo,bar" + * @final + */ + OPTION_LIST: 6, + /** + * @property Indicates that no count was specified for this command + * invocation. + * @final + */ COUNT_NONE: -1, - COUNT_ALL: -2, // :%... + /** + * @property Indicates that the full buffer range (1,$) was specified + * for this command invocation. + * @final + */ + // FIXME: this isn't a count at all + COUNT_ALL: -2, // :%... + /** @property {Iterator(Command)} @private */ __iterator__: function () { let sorted = exCommands.sort(function (a, b) a.name > b.name); return util.Array.itervalues(sorted); }, + /** + * Adds a new default command. + * + * @param {string[]} names The names by which this command can be + * invoked. The first name specified is the command's canonical + * name. + * @param {string} description A description of the command. + * @param {function} action The action invoked by this command. + * @param {Object} extra An optional extra configuration hash. + * @optional + */ add: function (names, description, action, extra) { return addCommand(new Command(names, description, action, extra), false, false); }, + /** + * Adds a new user-defined command. + * + * @param {string[]} names The names by which this command can be + * invoked. The first name specified is the command's canonical + * name. + * @param {string} description A description of the command. + * @param {function} action The action invoked by this command. + * @param {Object} extra An optional extra configuration hash. + * @param {boolean} replace Overwrite an existing command with the same + * canonical name. + */ addUserCommand: function (names, description, action, extra, replace) { extra = extra || {}; @@ -353,6 +498,13 @@ function Commands() //{{{ return addCommand(new Command(names, description, action, extra), true, replace); }, + /** + * Returns the specified command invocation object serialized to + * an executable Ex command string. + * + * @param {Object} args The command invocation object. + * @returns {string} + */ commandToString: function (args) { let res = [args.command + (args.bang ? "!" : "")]; @@ -373,111 +525,96 @@ function Commands() //{{{ return res.join(" "); }, + /** + * Returns the command with matching name. + * + * @param {string} name The name of the command to return. This can be + * any of the command's names. + * @returns {Command} + */ get: function (name) { return exCommands.filter(function (cmd) cmd.hasName(name))[0] || null; }, + /** + * Returns the user-defined command with matching name. + * + * @param {string} name The name of the command to return. This can be + * any of the command's names. + * @returns {Command} + */ getUserCommand: function (name) { return exCommands.filter(function (cmd) cmd.isUserCommand && cmd.hasName(name))[0] || null; }, + /** + * Returns all user-defined commands. + * + * @returns {Command[]} + */ getUserCommands: function () { return exCommands.filter(function (cmd) cmd.isUserCommand); }, - // returns [count, parsed_argument] - parseArg: function parseArg(str) - { - let arg = ""; - let quote = null; - let len = str.length; - - while (str.length && !/^\s/.test(str)) - { - let res; - - switch (QUOTE_STYLE) - { - case "vim-sucks": - if (res = str.match = str.match(/^()((?:[^\\\s]|\\.)+)((?:\\$)?)/)) - arg += res[2].replace(/\\(.)/g, "$1"); - break; - - case "vimperator": - if (res = str.match(/^()((?:[^\\\s"']|\\.)+)((?:\\$)?)/)) - arg += res[2].replace(/\\(.)/g, "$1"); - else if (res = str.match(/^(")((?:[^\\"]|\\.)*)("?)/)) - arg += eval(res[0] + (res[3] ? "" : '"')); - else if (res = str.match(/^(')((?:[^\\']|\\.)*)('?)/)) - arg += res[2].replace(/\\(.)/g, function (n0, n1) /[\\']/.test(n1) ? n1 : n0); - break; - - case "rc-ish": - if (res = str.match = str.match(/^()((?:[^\\\s"']|\\.)+)((?:\\$)?)/)) - arg += res[2].replace(/\\(.)/g, "$1"); - else if (res = str.match(/^(")((?:[^\\"]|\\.)*)("?)/)) - arg += eval(res[0] + (res[3] ? "" : '"')); - else if (res = str.match(/^(')((?:[^']|'')*)('?)/)) - arg += res[2].replace("''", "'", "g"); - break; - - case "pythonesque": - if (res = str.match = str.match(/^()((?:[^\\\s"']|\\.)+)((?:\\$)?)/)) - arg += res[2].replace(/\\(.)/g, "$1"); - else if (res = str.match(/^(""")((?:.?.?[^"])*)((?:""")?)/)) - arg += res[2]; - else if (res = str.match(/^(")((?:[^\\"]|\\.)*)("?)/)) - arg += eval(res[0] + (res[3] ? "" : '"')); - else if (res = str.match(/^(')((?:[^\\']|\\.)*)('?)/)) - arg += res[2].replace(/\\(.)/g, function (n0, n1) /[\\']/.test(n1) ? n1 : n0); - break; - } - - if (!res) - break; - if (!res[3]) - quote = res[1]; - if (!res[1]) - quote = res[3]; - str = str.substr(res[0].length); - } - - return [len - str.length, arg, quote]; - }, - - // in '-quoted strings, only ' and \ itself are escaped - // in "-quoted strings, also ", \n and \t are translated - // in non-quoted strings everything is taken literally apart from "\ " and "\\" - // - // @param str: something like "-x=foo -opt=bar arg1 arg2" - // "options" is an array [name, type, validator, completions] and could look like: - // options = [[["-force"], OPTION_NOARG], - // [["-fullscreen", "-f"], OPTION_BOOL], - // [["-language"], OPTION_STRING, validateFunc, ["perl", "ruby"]], - // [["-speed"], OPTION_INT], - // [["-acceleration"], OPTION_FLOAT], - // [["-accessories"], OPTION_LIST, null, ["foo", "bar"]], - // [["-other"], OPTION_ANY]]; - // @param argCount can be: - // "0": no arguments - // "1": exactly one argument - // "+": one or more arguments - // "*": zero or more arguments (default if unspecified) - // "?": zero or one arguments - // @param allowUnknownOptions: -foo won't result in an error, if -foo isn't - // specified in "options" // TODO: should it handle comments? // : it might be nice to be able to specify that certain quoting // should be disabled E.g. backslash without having to resort to - // using literal etc + // using literal etc. + // : I'm not sure documenting the returned object here, and + // elsewhere, as type Args rather than simply Object makes sense, + // especially since it is further augmented for use in + // Command#action etc. + /** + * Parses str for options and plain arguments. + * + * The returned Args object is an augmented array of arguments. + * Any key/value pairs of extra will be available and the + * following additional properties: + * -opt - the value of the option -opt if specified + * string - the original argument string str + * literalArg - any trailing literal argument + * + * Quoting rules: + * '-quoted strings - only ' and \ itself are escaped + * "-quoted strings - also ", \n and \t are translated + * non-quoted strings - everything is taken literally apart from "\ + * " and "\\" + * + * @param {string} str The Ex command-line string to parse. E.g. + * "-x=foo -opt=bar arg1 arg2" + * @param {Array} options The options accepted. These are specified as + * an array [name, type, validator, completions]. E.g. + * options = [[["-force"], OPTION_NOARG], + * [["-fullscreen", "-f"], OPTION_BOOL], + * [["-language"], OPTION_STRING, validateFunc, ["perl", "ruby"]], + * [["-speed"], OPTION_INT], + * [["-acceleration"], OPTION_FLOAT], + * [["-accessories"], OPTION_LIST, null, ["foo", "bar"]], + * [["-other"], OPTION_ANY]]; + * @param {string} argCount The number of arguments accepted. + * "0": no arguments + * "1": exactly one argument + * "+": one or more arguments + * "*": zero or more arguments (default if unspecified) + * "?": zero or one arguments + * @param {boolean} allowUnknownOptions Whether unspecified options + * should cause an error. + * @param {number} literal The index at which any literal arg begins. + * See {@link Command#literal}. + * @param {CompletionContext} complete The relevant completion context + * when the args are being parsed for completion. + * @param {Object} extra Extra keys to be spliced into the returned + * Args object. + * @returns {Args} + */ parseArgs: function (str, options, argCount, allowUnknownOptions, literal, complete, extra) { function getNextArg(str) { - let [count, arg, quote] = commands.parseArg(str); + let [count, arg, quote] = parseArg(str); if (quote == "\\" && !complete) return [,,,"Trailing \\"]; if (quote && !complete) @@ -737,6 +874,21 @@ function Commands() //{{{ return args; }, + /** + * Parses a complete Ex command. + * + * The parsed string is returned as an Array like + * [count, command, bang, args]: + * count - any count specified + * command - the Ex command name + * bang - whether the special "bang" version was called + * args - the commands full argument string + * E.g. ":2foo! bar" -> [2, "foo", true, "bar"] + * + * @param {string} str The Ex command line string. + * @returns {Array} + */ + // FIXME: why does this return an Array rather than Object? parseCommand: function (str) { // remove comments @@ -759,16 +911,37 @@ function Commands() //{{{ return [count, cmd, !!special, args || ""]; }, - get complQuote() complQuote, + /** @property @private */ + get complQuote() complQuote, // XXX: needed? - get quoteArg() quoteArg, + /** @property @private */ + get quoteArg() quoteArg, // XXX: needed? + /** + * Remove the user-defined command with matching name. + * + * @param {string} name The name of the command to remove. This can be + * any of the command's names. + */ removeUserCommand: function (name) { exCommands = exCommands.filter(function (cmd) !(cmd.isUserCommand && cmd.hasName(name))); }, - // FIXME: still belong here? Also used for autocommand parameters + // FIXME: still belong here? Also used for autocommand parameters. + /** + * Returns a string with all tokens in string matching "" + * replaced with "value". Where "key" is a property of the specified + * tokens object and "value" is the corresponding value. The + * token can be used to include a literal "<" in the returned + * string. Any tokens prefixed with "q-" will be quoted except for + * which is treated like . + * + * @param {string} str The string with tokens to replace. + * @param {Object} tokens A map object whose keys are replaced with its + * values. + * @returns {string} + */ replaceTokens: function replaceTokens(str, tokens) { return str.replace(/<((?:q-)?)([a-zA-Z]+)?>/g, function (match, quote, token) diff --git a/common/content/editor.js b/common/content/editor.js index 4245b5ad..d6570788 100644 --- a/common/content/editor.js +++ b/common/content/editor.js @@ -1062,7 +1062,8 @@ function Editor() //{{{ /** * Expands an abbreviation in the currently active textbox. * - * @param {string} filter The mode filter. (@see #addAbbreviation) + * @param {string} filter The mode filter. + * @see #addAbbreviation */ expandAbbreviation: function (filter) { @@ -1099,10 +1100,10 @@ function Editor() //{{{ /** * Returns all abbreviations matching filter and lhs. * - * @param {string} filter The mode filter. (@see #addAbbreviation) + * @param {string} filter The mode filter. * @param {string} lhs The LHS of the abbreviation. - * (@see #addAbbreviation) * @returns {Array} The matching abbreviations [mode, lhs, rhs] + * @see #addAbbreviation */ getAbbreviations: function (filter, lhs) { @@ -1115,9 +1116,9 @@ function Editor() //{{{ /** * Lists all abbreviations matching filter and lhs. * - * @param {string} filter The mode filter. (@see #addAbbreviation) + * @param {string} filter The mode filter. * @param {string} lhs The LHS of the abbreviation. - * (@see #addAbbreviation) + * @see #addAbbreviation */ listAbbreviations: function (filter, lhs) { @@ -1143,9 +1144,9 @@ function Editor() //{{{ /** * Deletes all abbreviations matching filter and lhs. * - * @param {string} filter The mode filter. (@see #addAbbreviation) + * @param {string} filter The mode filter. * @param {string} lhs The LHS of the abbreviation. - * (@see #addAbbreviation) + * @see #addAbbreviation */ removeAbbreviation: function (filter, lhs) { @@ -1196,7 +1197,8 @@ function Editor() //{{{ /** * Removes all abbreviations matching filter. * - * @param {string} filter The mode filter. (@see #addAbbreviation) + * @param {string} filter The mode filter. + * @see #addAbbreviation */ removeAllAbbreviations: function (filter) { diff --git a/common/content/hints.js b/common/content/hints.js index eefa9a7b..5d698827 100644 --- a/common/content/hints.js +++ b/common/content/hints.js @@ -136,9 +136,9 @@ function Hints() //{{{ * If it finds a hint it returns it, if the hint is not the caption of the * element it will return showtext=true. * - * @param {object} elem The element. + * @param {Object} elem The element. * @param {string} tagname Its tagname. - * @param {doc} The document it is in. + * @param {Document} doc The document it is in. * * @returns [text, showtext] */ @@ -201,9 +201,9 @@ function Hints() //{{{ * * Only called by generate() * - * @param {object} elem The element. - * @param {Number} leftpos The left offset of the image. - * @param {Number} toppos The top offset of the image. + * @param {Object} elem The element. + * @param {number} leftpos The left offset of the image. + * @param {number} toppos The top offset of the image. * @returns [leftpos, toppos] The updated offsets. */ function getAreaOffset(elem, leftpos, toppos) @@ -274,7 +274,7 @@ function Hints() //{{{ * * Pushes the hints into the pageHints object, but does not display them. * - * @param {object} win The window,defaults to window.content + * @param {Window} win The window,defaults to window.content */ function generate(win) { @@ -368,7 +368,7 @@ function Hints() //{{{ /** * Toggle the highlight of a hint. * - * @param {object} elem The element to toggle. + * @param {Object} elem The element to toggle. * @param {boolean} active Whether it is the currently active hint or not. */ function setClass(elem, active) diff --git a/common/content/liberator.js b/common/content/liberator.js index 0b1cf852..0cc25271 100644 --- a/common/content/liberator.js +++ b/common/content/liberator.js @@ -633,7 +633,6 @@ const liberator = (function () //{{{ // "complete" // TODO: "zoom": if the zoom value of the current buffer changed // TODO: move to ui.js? - // Yes --djk registerCallback: function (type, mode, func) { if (!(type in callbacks)) diff --git a/common/content/mappings.js b/common/content/mappings.js index d110a4c2..c7c4fabe 100644 --- a/common/content/mappings.js +++ b/common/content/mappings.js @@ -41,10 +41,11 @@ the terms of any one of the MPL, the GPL or the LGPL. * @param {function} action The action invoked by each key sequence. * @param {Object} extraInfo An optional extra configuration hash. The * following properties are supported. - * flags - See (@link Map#flags) - * noremap - See (@link Map#noremap) - * rhs - See (@link Map#rhs) - * silent - See (@link Map#silent) + * flags - see {@link Map#flags} + * noremap - see {@link Map#noremap} + * rhs - see {@link Map#rhs} + * silent - see {@link Map#silent} + * @optional * @private */ function Map(modes, keys, description, action, extraInfo) //{{{ @@ -59,7 +60,8 @@ function Map(modes, keys, description, action, extraInfo) //{{{ /** @property {function (number)} The function called to execute this mapping. */ this.action = action; - /** @property {number} See (@link Mappings#flags) */ + /** @property {number} @see Mappings#flags */ + // FIXME: flags is incongruent with the other properties this.flags = extraInfo.flags || 0; /** @property {string} This mapping's description, as shown in :viusage. */ this.description = description || ""; @@ -69,7 +71,7 @@ function Map(modes, keys, description, action, extraInfo) //{{{ this.noremap = extraInfo.noremap || false; /** @property {boolean} Whether any output from the mapping should be echoed on the command line. */ this.silent = extraInfo.silent || false; -}; +} Map.prototype = { @@ -329,6 +331,7 @@ function Mappings() //{{{ return { // NOTE: just normal mode for now + /** @property {Iterator(Map)} @private */ __iterator__: function () mappingsIterator([modes.NORMAL], main), // used by :mkvimperatorrc to save mappings @@ -342,7 +345,7 @@ function Mappings() //{{{ getUserIterator: function (mode) mappingsIterator(mode, user), /** - * Add a new default key mapping. + * Adds a new default key mapping. * * @param {number[]} modes The modes that this mapping applies to. * @param {string[]} keys The key sequences which are bound to @@ -350,6 +353,7 @@ function Mappings() //{{{ * @param {string} description A description of the key mapping. * @param {function} action The action invoked by each key sequence. * @param {Object} extra An optional extra configuration hash. + * @optional */ add: function (modes, keys, description, action, extra) { @@ -357,14 +361,16 @@ function Mappings() //{{{ }, /** - * Add a new user-defined key mapping. + * Adds a new user-defined key mapping. * * @param {number[]} modes The modes that this mapping applies to. * @param {string[]} keys The key sequences which are bound to * action. * @param {string} description A description of the key mapping. * @param {function} action The action invoked by each key sequence. - * @param {Object} extra An optional extra configuration hash. + * @param {Object} extra An optional extra configuration hash (see + * {@link Map#extraInfo}). + * @optional */ addUserMap: function (modes, keys, description, action, extra) { diff --git a/common/content/options.js b/common/content/options.js index da19b982..76f77fd1 100644 --- a/common/content/options.js +++ b/common/content/options.js @@ -30,30 +30,92 @@ the terms of any one of the MPL, the GPL or the LGPL. // do NOT create instances of this class yourself, use the helper method // options.add() instead +/** + * A class representing configuration options. Instances are created by the + * {@link Options} class. + * + * @param {string[]} names The names by which this option is identified. + * @param {string} description A short one line description of the option. + * @param {string} type The option's value data type (see {@link Option#type}). + * @param {string} defaultValue The default value for this option. + * @param {Object} extraInfo An optional extra configuration hash. The + * following properties are supported. + * scope - see {@link Option#scope} + * setter - see {@link Option#setter} + * getter - see {@link Option#getter} + * completer - see {@link Option#completer} + * valdator - see {@link Option#validator} + * checkHas - see {@link Option#checkHas} + * @optional + * @private + */ function Option(names, description, type, defaultValue, extraInfo) //{{{ { if (!extraInfo) extraInfo = {}; + /** @property {string} The option's canonical name. */ this.name = names[0]; + /** @property {string[]} All names by which this option is identified. */ this.names = names; + /** + * @property {string} The option's data type. One of: + * "boolean" - Boolean E.g. true + * "number" - Integer E.g. 1 + * "string" - String E.g. "Vimperator" + * "charlist" - Character list E.g. "rb" + * "stringlist" - String list E.g. "homepage,quickmark,tabopen,paste" + */ this.type = type; - this.scope = (extraInfo.scope & options.OPTION_SCOPE_BOTH) || - options.OPTION_SCOPE_GLOBAL; - // XXX set to BOTH by default someday? - kstep + /** + * @property {number} The scope of the option. This can be local, global, + * or both. + * @see Options#OPTION_SCOPE_LOCAL + * @see Options#OPTION_SCOPE_GLOBAL + * @see Options#OPTION_SCOPE_BOTH + */ + this.scope = (extraInfo.scope & options.OPTION_SCOPE_BOTH) || options.OPTION_SCOPE_GLOBAL; // XXX set to BOTH by default someday? - kstep + /** + * @property {string} This option's description, as shown in :optionusage. + */ this.description = description || ""; - // "", 0 are valid default values - this.defaultValue = (defaultValue === undefined) ? null : defaultValue; + /** + * @property {value} The option's default value. This value will be used + * unless the option is explicitly set either interactively or in an RC + * file or plugin. + */ + this.defaultValue = (defaultValue === undefined) ? null : defaultValue; // "", 0 are valid default values + /** + * @property {function} The function called when the option value is set. + */ this.setter = extraInfo.setter || null; + /** + * @property {function} The function called when the option value is read. + */ this.getter = extraInfo.getter || null; + /** + * @property {function(CompletionContext, Args)} This option's completer. + * @see CompletionContext + */ this.completer = extraInfo.completer || null; + /** + * @property {function} The function called to validate the option's value + * when set. + */ this.validator = extraInfo.validator || null; + /** + * @property The function called to determine whether the option already + * contains a specified value. + * @see #has + */ this.checkHas = extraInfo.checkHas || null; - - // this property is set to true whenever the option is first set - // useful to see whether it was changed by some rc file + /** + * @property {boolean} Set to true whenever the option is first set. This + * is useful to see whether it was changed from its default value + * interactively or by some RC file. + */ this.hasChanged = false; // add no{option} variant of boolean {option} to this.names @@ -70,10 +132,20 @@ function Option(names, description, type, defaultValue, extraInfo) //{{{ if (this.globalvalue == undefined) this.globalvalue = this.defaultValue; } + Option.prototype = { + + /** @property {value} The option's global value. @see #scope */ get globalvalue() options.store.get(this.name), set globalvalue(val) { options.store.set(this.name, val); }, + /** + * Returns value as an array of parsed values if the option type is + * "charlist" or "stringlist" or else unchanged. + * + * @param {value} value The option value. + * @returns {value|string[]} + */ parseValues: function (value) { if (this.type == "stringlist") @@ -83,6 +155,13 @@ Option.prototype = { return value; }, + /** + * Returns values packed in the appropriate format for the option + * type. + * + * @param {value|string[]} values The option value. + * @returns {value} + */ joinValues: function (values) { if (this.type == "stringlist") @@ -92,16 +171,41 @@ Option.prototype = { return values; }, + /** @property {value|string[]} The option value or array of values. */ get values() this.parseValues(this.value), set values(values) this.setValues(values, this.scope), + /** + * Returns the option's value as an array of parsed values if the option + * type is "charlist" or "stringlist" or else the simple value. + * + * @param {number} scope The scope to return these values from (see + * {@link Option#scope}). + * @returns {value|string[]} + */ getValues: function (scope) this.parseValues(this.get(scope)), + /** + * Sets the option's value from an array of values if the option type is + * "charlist" or "stringlist" or else the simple value. + * + * @param {number} scope The scope to apply these values to (see + * {@link Option#scope}). + */ setValues: function (values, scope) { this.set(this.joinValues(values), scope || this.scope); }, + /** + * Returns the value of the option in the specified scope. The + * (@link Option#getter) callback, if it exists, is invoked with this value + * before it is returned. + * + * @param {number} scope The scope to return this value from (see + * {@link Option#scope}). + * @returns {value} + */ get: function (scope) { if (scope) @@ -127,6 +231,15 @@ Option.prototype = { return aValue; }, + /** + * Sets the option value to newValue for the specified scope. + * The (@link Option#setter) callback, if it exists, is invoked with + * newValue. + * + * @param {value} newValue The option's new value. + * @param {number} scope The scope to apply this value to (see + * {@link Option#scope}). + */ set: function (newValue, scope) { scope = scope || this.scope; @@ -153,9 +266,19 @@ Option.prototype = { this.hasChanged = true; }, + /** + * @property {value} The option's current value. The option's local value, + * or if no local value is set, this is equal to the (@link #globalvalue). + */ get value() this.get(), set value(val) this.set(val), + /** + * Returns whether the option value contains one or more of the specified + * arguments. + * + * @returns {boolean} + */ has: function () { let self = this; @@ -167,8 +290,18 @@ Option.prototype = { return Array.some(arguments, function (val) test(val)); }, + /** + * Returns whether this option is identified by name. + * + * @param {string} name + * @returns {boolean} + */ hasName: function (name) this.names.indexOf(name) >= 0, + /** + * Returns whether the specified values are valid for this option. + * @see Option#validator + */ isValidValue: function (values) { if (this.validator) @@ -177,11 +310,23 @@ Option.prototype = { return true; }, + /** + * Resets the option to its default value. + */ reset: function () { this.value = this.defaultValue; }, + /** + * Sets the option's value using the specified set operator. + * + * @param {string} operator The set operator. + * @param {value|string[]} values The value (or values) to apply. + * @param {number} scope The scope to apply this value to (see + * {@link #scope}). + * @param {boolean} invert Whether this is an invert boolean operation. + */ op: function (operator, values, scope, invert) { let newValue = null; @@ -281,15 +426,23 @@ Option.prototype = { this.setValues(newValue, scope); } }; - // TODO: Run this by default? + +// TODO: Run this by default? +/** + * Validates the specified values against values generated by the + * option's completer function. + * + * @param {value|string[]} values The value or array of values to validate. + * @returns {boolean} + */ Option.validateCompleter = function (values) { + liberator.log(values instanceof Array) let context = CompletionContext(""); let res = context.fork("", 0, this, this.completer); if (!res) res = context.allItems.items.map(function (item) [item.text]); - return Array.concat(values).every( - function (value) res.some(function (item) item[0] == value)); + return Array.concat(values).every(function (value) res.some(function (item) item[0] == value)); }; //}}} /** @@ -807,16 +960,33 @@ function Options() //{{{ const self = { + /** + * @property {number} Global option scope. + * @final + */ OPTION_SCOPE_GLOBAL: 1, - OPTION_SCOPE_LOCAL: 2, - OPTION_SCOPE_BOTH: 3, + /** + * @property {number} Local option scope. Options in this scope only + * apply to the current tab/buffer. + * @final + */ + OPTION_SCOPE_LOCAL: 2, + + /** + * @property {number} Both local and global option scope. + * @final + */ + OPTION_SCOPE_BOTH: 3, + + /** @property {Iterator(Option)} @private */ __iterator__: function () { let sorted = [o for ([i, o] in Iterator(optionHash))].sort(function (a, b) String.localeCompare(a.name, b.name)); return (v for ([k, v] in Iterator(sorted))); }, + /** @property {Object} Observes preference value changes. */ prefObserver: { register: function () { @@ -848,6 +1018,18 @@ function Options() //{{{ } }, + /** + * Adds a new option. + * + * @param {string[]} names All names for the option. + * @param {string} description A description of the option. + * @param {string} type The option type (see {@link Option#type}). + * @param {value} defaultValue The option's default value. + * @param {Object} extra An optional extra configuration hash (see + * {@link Map#extraInfo}). + * @optional + * @returns {boolean} Whether the option was created. + */ add: function (names, description, type, defaultValue, extraInfo) { if (!extraInfo) @@ -873,6 +1055,14 @@ function Options() //{{{ return true; }, + /** + * Returns the option with name in the specified scope. + * + * @param {string} name The option's name. + * @param {number} scope The option's scope (see {@link Option#scope}). + * @optional + * @returns {Option} The matching option. + */ get: function (name, scope) { if (!scope) @@ -890,6 +1080,15 @@ function Options() //{{{ return null; }, + /** + * Lists all options in scope or only those with changed values + * if onlyNonDefault is specified. + * + * @param {boolean} onlyNonDefault Limit the list to prefs with a + * non-default value. + * @param {number} scope Only list options in this scope (see + * {@link Option#scope}). + */ list: function (onlyNonDefault, scope) { if (!scope) @@ -929,6 +1128,16 @@ function Options() //{{{ commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE); }, + /** + * Lists all preferences matching filter or only those with + * changed values if onlyNonDefault is specified. + * + * @param {boolean} onlyNonDefault Limit the list to prefs with a + * non-default value. + * @param {string} filter The list filter. A null filter lists all + * prefs. + * @optional + */ listPrefs: function (onlyNonDefault, filter) { if (!filter) @@ -961,6 +1170,15 @@ function Options() //{{{ commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE); }, + /** + * Parses a :set command. + * + * @param {string} args The :set command's argument string. + * @param {Object} modifiers A hash of parsing modifiers. These are: + * scope - see {@link Option#scope} + * @optional + * @returns {Object} The parsed command object. + */ parseOpt: function parseOpt(args, modifiers) { let ret = {}; @@ -1005,15 +1223,29 @@ function Options() //{{{ return ret; }, + /** @property {Object} The options store. */ get store() storage.options, + /** + * Returns the value of the preference name. + * + * @param {string} name The preference name. + * @param {value} forcedDefault The the default value for this + * preference. Used for internal liberator preferences. + */ getPref: function (name, forcedDefault) { return loadPreference(name, forcedDefault); }, - // Set a pref, but warn the user if it's changed from its default - // value. + /** + * Sets the preference name to value but warns the user + * if the value is changed from its default. + * + * @param {string} name The preference name. + * @param {value} value The new preference value. + */ + // FIXME: Well it used to. I'm looking at you mst! --djk safeSetPref: function (name, value) { let val = loadPreference(name, null, false); @@ -1025,11 +1257,22 @@ function Options() //{{{ storePreference(SAVED + name, value); }, + /** + * Sets the preference name to value. + * + * @param {string} name The preference name. + * @param {value} value The new preference value. + */ setPref: function (name, value) { storePreference(name, value); }, + /** + * Resets the preference name to its default value. + * + * @param {string} name The preference name. + */ resetPref: function (name) { try @@ -1042,7 +1285,11 @@ function Options() //{{{ } }, - // this works only for booleans + /** + * Toggles the value of the boolean preference name. + * + * @param {string} name The preference name. + */ invertPref: function (name) { if (services.get("pref").getPrefType(name) == Ci.nsIPrefBranch.PREF_BOOL) @@ -1079,7 +1326,7 @@ function Options() //{{{ * previous values. * * @param {function} fn The function to call. - * @param {object} fn The 'this' object with which to call fn + * @param {Object} fn The 'this' object with which to call fn * @see #pushContext * @see #popContext */ diff --git a/common/content/tabs.js b/common/content/tabs.js index 6eb98d67..2ca99ba3 100644 --- a/common/content/tabs.js +++ b/common/content/tabs.js @@ -1229,7 +1229,7 @@ function Tabs() //{{{ // shouldn't be one yet. /** * Called on each TabSelect event to update the tab selection history. - * See (@link tabs.alternate). + * @see tabs#alternate */ updateSelectionHistory: function () { diff --git a/common/content/ui.js b/common/content/ui.js index 1c12a382..52357f99 100644 --- a/common/content/ui.js +++ b/common/content/ui.js @@ -1220,7 +1220,7 @@ function CommandLine() //{{{ * * @param {string} prompt The input prompt to use. * @param {function(string)} callback - * @param {object} extra + * @param {Object} extra * @... {function} onChange - A function to be called with the current * input every time it changes. * @... {function(CompletionContext)} completer - A completion function