diff --git a/chrome/content/vimperator/commands.js b/chrome/content/vimperator/commands.js index 63b85da4..871133ea 100644 --- a/chrome/content/vimperator/commands.js +++ b/chrome/content/vimperator/commands.js @@ -586,6 +586,75 @@ function Commands() //{{{ "The special version :javascript! will open the JavaScript console of Firefox." } )); + addDefaultCommand(new Command(["let"], + function(args) + { + if (!args) + { + return; + // List all defined variables + } + + var match; + // 1 - type, 2 - name, 3 - +-., 4 - expr + if (match = args.match(/([$@&])?([\w:]+)\s*([+-.])?=\s*(.+)/)) + { + if (!match[1]) + { + var reference = vimperator.variableReference(match[2]); + if (!reference[0] && match[3]) + return vimperator.echoerr("E121: Undefined variable: " + match[2]); + + var expr = vimperator.eval(match[4]); + if (typeof expr === undefined) + return vimperator.echoerr("E15: Invalid expression: " + match[4]); + else + { + if (!reference[0] && reference[2] == 'g') + reference[0] = vimperator.globalVariables; + else + return; // for now + + if (match[3]) + { + if (match[3] == '+') + reference[0][reference[1]] += expr; + else if (match[3] == '-') + reference[0][reference[1]] -= expr; + else if (match[3] == '.') + reference[0][reference[1]] += expr.toString(); + } + else + reference[0][reference[1]] = expr; + } + } + } + // 1 - name + else if (match = args.match(/^\s*([\w:]+)\s*$/)) + { + var reference = vimperator.variableReference(match[1]); + if (!reference[0]) + return vimperator.echoerr("E121: Undefined variable: " + match[1]); + + var value = reference[0][reference[1]]; + if (typeof value == 'number') + var prefix = '#'; + else if (typeof value == 'function') + var prefix = '*'; + else + var prefix = ''; + vimperator.echo(reference[1] + '\t\t' + prefix + value); + } + }, + { + usage: ["let {var-name} [+-.]= {expr1}", "let {var-name}", "let"], + short_help: "Sets or lists a variable", + help: "Sets the variable {var-name} " + + "to the value of the expression {expr1}." + + "If no expression is given, the value of the variable is displayed." + + "Without arguments, displays a list of all variables." + } + )); addDefaultCommand(new Command(["map"], // 0 args -> list all maps // 1 arg -> list the maps starting with args @@ -1237,6 +1306,35 @@ function Commands() //{{{ help: "If a count is given, don't close the last but the [count]th last tab." } )); + addDefaultCommand(new Command(["unl[et]"], + function(args, special) + { + if (!args) + return vimperator.echoerr("E471: Argument required"); + + var names = args.split(/ /); + if (typeof names == 'string') names = [names]; + var length = names.length; + for (var i = 0, name = names[i]; i < length; name = names[++i]) + { + var reference = vimperator.variableReference(name); + if (!reference[0]) + { + if (!special) + vimperator.echoerr("E108: No such variable: " + name); + return; + } + + delete reference[0][reference[1]]; + } + }, + { + usage: ["unl[et][!] {name} ..."], + short_help: "Deletes a variable.", + help: "Deletes the variable {name}." + + "Several variable names can be given." + } + )); addDefaultCommand(new Command(["unm[ap]"], function(args) { diff --git a/chrome/content/vimperator/vimperator.js b/chrome/content/vimperator/vimperator.js index 946f05fa..43cd8d6b 100644 --- a/chrome/content/vimperator/vimperator.js +++ b/chrome/content/vimperator/vimperator.js @@ -247,6 +247,75 @@ const vimperator = (function() //{{{ return new LocalFile(path, mode, perms, tmp); }, + // partial sixth level expression evaluation + eval: function(string) + { + string = string.toString().replace(/^\s*/, '').replace(/\s*$/, ''); + var match = string.match(/^&(\w+)/); + if (match) + { + var opt = this.options.get(match[1]); + if (!opt) + { + this.echoerr('E113: Unknown option: ' + match[1]); + return; + } + var type = opt.type; + var value = opt.getter(); + if (type != 'boolean' && type != 'number') + value = value.toString(); + return value; + } + + // String + if (match = string.match(/^(['"])([^\1]*?[^\\]?)\1/)) + { + if (match) + return match[2].toString(); + else + { + this.echoerr('E115: Missing quote: ' + string); + return; + } + } + + // Number + if (match = string.match(/^(\d+)$/)) + { + return parseInt(match[1]); + } + + var reference = this.variableReference(string); + if (!reference[0]) + this.echoerr('E121: Undefined variable: ' + string); + else + return reference[0][reference[1]]; + + return; + }, + variableReference: function(string) + { + if (!string) return [null, null, null]; + if (match = string.match(/^([bwtglsv]):(\w+)/)) // Variable + { + // Other variables should be implemented + if (match[1] == 'g') + { + if (match[2] in this.globalVariables) + return [this.globalVariables, match[2], match[1]]; + else + return [null, match[2], match[1]]; + } + } + else // Global variable + { + if (string in this.globalVariables) + return [this.globalVariables, string, 'g']; + else + return [null, string, 'g']; + } + }, + // logs a message to the javascript error console log: function(msg, level) { @@ -513,6 +582,8 @@ const vimperator = (function() //{{{ vimperator.echo = vimperator.commandline.echo; vimperator.echoerr = vimperator.commandline.echoErr; + vimperator.globalVariables = {}; + // TODO: move elsewhere vimperator.registerCallback("submit", vimperator.modes.EX, function(command) { vimperator.execute(command); } ); vimperator.registerCallback("complete", vimperator.modes.EX, function(str) { return vimperator.completion.exTabCompletion(str); } );