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); } );