diff --git a/NEWS b/NEWS index fad60169..f5686204 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ special versions for the old behavior * IMPORTANT: renamed Startup and Quit autocmd events to VimperatorEnter and VimperatorLeave respectively + * add -nargs, -bang, and -count attribute support to :command * much improved completion support, including javascript, option, and search keyword * add / and / command-line mappings for selecting the previous and next history items @@ -53,7 +54,7 @@ * IMPORTANT: removed old :buffers! buffer window, as it was ugly and slightly broken use "B" or :buffers instead * IMPORTANT: input fields are not blured anymore by default after a page has loaded - use :set [no]focuscontent to control the behavior (thanks Paul Sobey for the + use :set [no]focuscontent to control the behavior (thanks Paul Sobey for the generous donation which made this behavior possible) * IMPORTANT: ctrl-x/a never take possible negative URLs into account, it was just too unpredictable @@ -67,7 +68,7 @@ * add :bn[ext], :bp[revious], :bN[ext] to switch to next/previous tab * add :pagestyle command to allow for switching between alternate style sheets * add :b# to select the alternate buffer - * add :tabduplicate command + * add :tabduplicate command * new 'urlseparator' option for specifying the regexp used to split the arg to :open, :tabopen and :winopen * :set editor now accepts quoting/escaping to use an editor with spaces in the path @@ -205,7 +206,7 @@ * new :time command for profiling * added new :sidebar and :sbclose commands * added 'more' and standard more-prompt key mappings to control - behaviour of the message list pager + behaviour of the message list pager * added 'hlsearchstyle' option to allow for user CSS styling of the highlighted text strings when 'hlsearch' is set * added 'linksearch' option to restrict page searches to link text - \L @@ -323,7 +324,6 @@ * showmode setting which shows the current mode in the command line (patch from Виктор Кожухаров) * gh goes home :) gH in a new tab * :open! bypasses cache - * :buffer and :buffers support (patch from Lars Kindler) * added :edit, :e and :tabedit aliases for :open, :tabopen * settings can now be changed with += and -= like in vim (patch from Виктор Кожухаров) diff --git a/content/commands.js b/content/commands.js index 4c9570ba..e684e60e 100644 --- a/content/commands.js +++ b/content/commands.js @@ -235,6 +235,8 @@ liberator.Commands = function () //{{{ description = description || "User defined command"; var command = new liberator.Command(names, description, action, extra); + // FIXME: shouldn't this be testing for an existing command by name? + // Requiring uppercase user command names like Vim would be easier if (!command) return false; @@ -255,6 +257,7 @@ liberator.Commands = function () //{{{ } exCommands.push(command); + return true; }, @@ -318,7 +321,7 @@ liberator.Commands = function () //{{{ parseArgs: function (str, options, argCount, allowUnknownOptions) //{{{ { // returns [count, parsed_argument] - function getNextArg(str) + function getNextArg(str) // {{{ { var inSingleString = false; var inDoubleString = false; @@ -415,7 +418,7 @@ liberator.Commands = function () //{{{ return [-1, "trailing \\"]; else return [str.length, arg]; - } + } // }}} if (!options) options = []; @@ -426,6 +429,8 @@ liberator.Commands = function () //{{{ var args = {}; // parsed options args.arguments = []; // remaining arguments args.string = str; // for access to the unparsed string + // FIXME: quick hack! Best way to do this? -- djk + args.argumentsString = ""; var invalid = false; var onlyArgumentsRemaining = allowUnknownOptions || false; // after a -- has been found @@ -452,7 +457,7 @@ liberator.Commands = function () //{{{ } var optname = ""; - if (!onlyArgumentsRemaining) + if (!onlyArgumentsRemaining) //{{{ { for (let opt = 0; opt < options.length; opt++) { @@ -578,7 +583,11 @@ liberator.Commands = function () //{{{ } } } - } + } //}}} + + // FIXME: quick hack! -- djk + if (!args.argumentsString) + args.argumentsString = str.substr(i); // if not an option, treat this token as an argument var [count, arg] = getNextArg(sub); @@ -596,7 +605,7 @@ liberator.Commands = function () //{{{ if (arg != null) args.arguments.push(arg); - i += count; // hopefully count is always >0, otherwise we get an endless loop + i += count; // hopefully count is always > 0, otherwise we get an endless loop } // check for correct number of arguments @@ -674,53 +683,95 @@ liberator.Commands = function () //{{{ ////////////////////// COMMANDS //////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////{{{ + // TODO: Vim allows commands to be defined without {rep} if there are {attr}s + // specified - useful? commandManager.add(["com[mand]"], "List and define commands", function (args, special) { - if (args) + if (args.argumentsString) { - var res = args.match(/^(\w+)(?:\s+(.+))?$/); - if (!res) + let matches = args.argumentsString.match(/^(\w+)(?:\s+(.+))?$/); + + if (!matches) { liberator.echoerr("E182: Invalid command name"); - return false; + return; } - var [cmd, rep] = [res[1], res[2]]; + + var [cmd, rep] = [matches[1], matches[2]]; } if (rep) { - if (!liberator.commands.addUserCommand([cmd], + let nargsOpt = args["-nargs"] || "0"; + let bangOpt = "-bang" in args; + let countOpt = "-count" in args; + + if (!liberator.commands.addUserCommand( + [cmd], "User defined command", function (args, special, count, modifiers) { - var replaced = rep.replace("", args); - replaced = replaced.replace("", '"' + args.replace('"', '\\"', "g") + '"'); - replaced = replaced.replace("", "<"); + function replaceTokens(token) + { + let ret; + let quote = false; - liberator.execute(replaced); + // ignore quoting of like Vim, not needed for + if (/^$/.test(token)) + quote = true; + + token = token.replace("q-", ""); + + switch (token) + { + case "": + ret = args.argumentsString; + break; + case "": + ret = bangOpt ? (special ? "!" : "") : token; + break; + case "": + ret = countOpt ? (count > -1 ? count : 0) : token; + break; + case "": + ret = "<"; + break; + default: + ret = token; + } + + return quote ? '"' + ret.replace('"', '\\"', "g") + '"' : ret; + } + + liberator.execute(rep.replace(/<(?:q-)?[a-z]+>/g, replaceTokens)); }, { - bang: true, // FIXME: until we implement -bang + argCount: nargsOpt, + bang: bangOpt, + count: countOpt, replacementText: rep }, special) - ) + ) { liberator.echoerr("E174: Command already exists: add ! to replace it"); } } else { - var cmdlist = getMatchingUserCommands(cmd); - if (cmdlist.length > 0) + let cmds = getMatchingUserCommands(cmd); + + if (cmds.length > 0) { - var str = liberator.template.tabular(["Name", "Args", "Definition"], [], - ([cmd.name, - "*", - cmd.replacementText || "function () { ... }"] - for each (cmd in cmdlist))); + let str = liberator.template.tabular(["", "Name", "Args", "Range", "Definition"], ["padding-right: 2em;"], + ([cmd.bang ? "!" : " ", + cmd.name, + cmd.argCount, + cmd.count ? "0c" : "", + cmd.replacementText || "function () { ... }"] for each (cmd in cmds))); + liberator.commandline.echo(str, liberator.commandline.HL_NORMAL, liberator.commandline.FORCE_MULTILINE); } else @@ -731,10 +782,12 @@ liberator.Commands = function () //{{{ }, { bang: true, - completer: function (filter) liberator.completion.userCommand(filter) - /*options: [[["-nargs"], OPTION_STRING, function (arg) { return /^(0|1|\*|\?|\+)$/.test(arg); }], - [["-bang"], OPTION_NOARG], - [["-bar"], OPTION_NOARG]] */ + completer: function (filter) liberator.completion.userCommand(filter), + options: [ + [["-nargs"], commandManager.OPTION_STRING, function (arg) /^[01*?+]$/.test(arg), ["0", "1", "*", "?", "+"]], + [["-bang"], commandManager.OPTION_NOARG], + [["-count"], commandManager.OPTION_NOARG], + ] }); commandManager.add(["comc[lear]"], diff --git a/locale/en-US/autocommands.txt b/locale/en-US/autocommands.txt index ac5340cc..ce5419ed 100644 --- a/locale/en-US/autocommands.txt +++ b/locale/en-US/autocommands.txt @@ -58,15 +58,15 @@ section:Examples[autocmd-examples] Enable _passthrough_ mode on all Google sites: - :au LocationChange .* js modes.passAllKeys = /google\.com/.test(buffer.URL) + :autocmd LocationChange .* js modes.passAllKeys = /google\.com/.test(buffer.URL) Enable _passthrough_ mode on *some* Google sites: - :au LocationChange .* js modes.passAllKeys = /(www|mail)\.google\.com/.test(buffer.URL) + :autocmd LocationChange .* js modes.passAllKeys = /(www|mail)\.google\.com/.test(buffer.URL) Set the filetype to mail when editing email at Gmail: - :au LocationChange .* :set editor=gvim -f - :au LocationChange mail\.google\.com :set editor=gvim -f -c 'set ft=mail' + :autocmd LocationChange .* :set editor=gvim -f + :autocmd LocationChange mail\.google\.com :set editor=gvim -f -c 'set ft=mail' // vim: set syntax=asciidoc: diff --git a/locale/en-US/map.txt b/locale/en-US/map.txt index 24e4ee76..6fb3ec1a 100644 --- a/locale/en-US/map.txt +++ b/locale/en-US/map.txt @@ -55,8 +55,10 @@ ________________________________________________________________________________ ||:map|| ________________________________________________________________________________ Map the key sequence {lhs} to {rhs}. The {rhs} is remapped, allowing for -nested and recursive mappings. Mappings are NOT saved during sessions, make -sure you put them in your vimperatorrc file! +nested and recursive mappings. + +Warning: Mappings are NOT saved during sessions, make sure you put them in your +vimperatorrc file! ________________________________________________________________________________ @@ -66,8 +68,10 @@ ________________________________________________________________________________ ||:cmap|| ________________________________________________________________________________ Map the key sequence {lhs} to {rhs} (in Command-line mode). The {rhs} is -remapped, allowing for nested and recursive mappings. Mappings are NOT saved -during sessions, make sure you put them in your vimperatorrc file! +remapped, allowing for nested and recursive mappings. + +Warning: Mappings are NOT saved during sessions, make sure you put them in your +vimperatorrc file! ________________________________________________________________________________ @@ -77,8 +81,10 @@ ________________________________________________________________________________ ||:imap|| ________________________________________________________________________________ Map the key sequence {lhs} to {rhs} (in insert mode). The {rhs} is remapped, -allowing for nested and recursive mappings. Mappings are NOT saved during -sessions, make sure you put them in your vimperatorrc file! +allowing for nested and recursive mappings. + +Warning: Mappings are NOT saved during sessions, make sure you put them in your +vimperatorrc file! ________________________________________________________________________________ @@ -247,24 +253,61 @@ ________________________________________________________________________________ ||:com[mand][!] [{attr}...] {cmd} {rep}|| + ________________________________________________________________________________ -Define a new user command. The name of the command is {cmd} and its relacement -text is {rep}. The command's attributes are {attr}. If a command with this -name already exists an error is reported unless [!] is specified, in which case -the command is redefined. Unlike Vim, the command may start with a lowercase +Define a new user command. The name of the command is {cmd} and its relacement +text is {rep}. The command's attributes are {attr}. If a command with this name +already exists an error is reported unless [!] is specified, in which case the +command is redefined. Unlike Vim, the command may start with a lowercase letter. +The command's behavior can be specified by providing attributes when the +command is defined. + +|E175| |E176| |:command-nargs| + +Argument handling + +By default user commands accept no arguments. This can be changed by specifying +the -nargs attribute. + +The valid values are: +`----------`-------------------------------------------------------------------- +*-nargs=0* No arguments are allowed (default) +*-nargs=1* One argument is allowed +*-nargs=** Zero or more arguments are allowed +*-nargs=?* Zero or one argument is allowed +*-nargs=+* One or more argument is allowd +-------------------------------------------------------------------------------- + +|E177| |E178| |:command-count| + +Count handling + +By default user commands do not accept a count. Use the -count attribute if +you'd like to have a count passed to your user command. This will then be +available for expansion as in the argument. + +|:command-bang| + +Special cases + +By default a user command does not have a special version. i.e. a version +executed with the ! modifier. Providing the -bang attribute will enable this +and will be available in the argument. + +|:command-replacement-text| + +Replacement text + The replacement text {rep} is scanned for escape sequences and these are -replaced with values from the user entered command-line. The resulting string +replaced with values from the user entered command-line. The resulting string is then executed as an Ex command. The valid escape sequences are: `----------`-------------------------------------------------------------------- ** The command arguments exactly as supplied -** The command arguments quoted as a single value in a manner suitable for expression evaluation +** Any supplied count E.g. 5 +** ! if the command was executed with the ! modifier ** A literal '<' character to allow for a literal copy of one of the escape sequences. E.g. args> will expand to a literal -------------------------------------------------------------------------------- -Note: {attr} not implemented yet. +"q-" can be prefixed to the escape sequence so that the value is quoted, making +it suitable for expression evaluation. Example: ________________________________________________________________________________ @@ -281,4 +324,12 @@ ________________________________________________________________________________ Delete the user-defined command {cmd}. ________________________________________________________________________________ +section:Examples[command-examples] + +Add a :Google command to search via google: + + :command -nargs=* Google open google + +// TODO: add decent examples + // vim: set syntax=asciidoc: