diff --git a/NEWS b/NEWS index 4e5b0f59..1231c7ee 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,10 @@
2007-XX-XX: * version 0.5.2 + * statusline is now white on black with bold font by default (like in (g)vim) + (change with userChrome.css if you don't like it until we have :colorscheme) + * :let mapleader="," andin :map support + * added new :let and :unlet commands * separated search and Ex command history * added 'visualbellstyle' for styling/hiding the visual bell * merge the existing status bar with the standard FF status bar so that diff --git a/chrome/content/vimperator/commands.js b/chrome/content/vimperator/commands.js index 0f868897..ae40247e 100644 --- a/chrome/content/vimperator/commands.js +++ b/chrome/content/vimperator/commands.js @@ -604,6 +604,77 @@ 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]) { + if (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 @@ -618,6 +689,15 @@ function Commands() //{{{ var matches = args.match(/^([^\s]+)(?:\s+(.+))?$/) var [lhs, rhs] = [matches[1], matches[2]]; + var leader_reg = new RegExp('', 'i'); + + if (leader_reg.test(lhs)) + { + var leader_ref = vimperator.variableReference('mapleader'); + var leader = leader_ref[0] ? leader_ref[0][leader_ref[1]] : '\\'; + + lhs = lhs.replace(leader_reg, leader); + } if (rhs) { @@ -1338,6 +1418,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 6aa84e52..ed1d9a0a 100644 --- a/chrome/content/vimperator/vimperator.js +++ b/chrome/content/vimperator/vimperator.js @@ -359,6 +359,78 @@ 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 + else if (match = string.match(/^(['"])([^\1]*?[^\\]?)\1/)) + { + if (match) + return match[2].toString(); + else + { + this.echoerr("E115: Missing quote: " + string); + return; + } + } + + // Number + else 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) { @@ -383,10 +455,10 @@ const vimperator = (function() //{{{ } catch (e) { - value = ''; + value = ""; } - string += i + ': ' + value + '\n'; + string += i + ": " + value + "\n"; } vimperator.log(string, level); }, @@ -623,6 +695,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); } );