diff --git a/common/content/commandline.js b/common/content/commandline.js index 67f85d01..c79945b1 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -1165,7 +1165,7 @@ const CommandLine = Module("commandline", { dactyl.registerObserver("echoLine", observe, true); dactyl.registerObserver("echoMultiline", observe, true); function observe(str, highlight, dom) { - buffer.push(dom ? util.domToString(dom) : str) + buffer.push(dom && !isString(str) ? util.domToString(dom) : str) } dactyl.trapErrors.apply(dactyl, [fn, self].concat(Array.slice(arguments, 2))); return buffer.join("\n"); diff --git a/common/content/commands.js b/common/content/commands.js index 6c760c3c..92b1626b 100644 --- a/common/content/commands.js +++ b/common/content/commands.js @@ -145,8 +145,12 @@ const Command = Class("Command", { if (args.bang && !this.bang) throw FailedAssertion("E477: No ! allowed"); + dactyl.trapErrors(function exec(command) { - this.action(args, modifiers); + if (this.always) + this.always(args, modifiers); + if (!io.sourcing || !io.sourcing.noExecute) + this.action(args, modifiers); }, this); }, @@ -1245,6 +1249,62 @@ const Commands = Module("commands", { completer: function (context) completion.userCommand(context) }); + function checkStack(cmd) { + util.assert(io.sourcing && io.sourcing.stack && + io.sourcing.stack[cmd] && io.sourcing.stack[cmd].length, + "Invalid use of conditional"); + } + function pop(cmd) { + checkStack(cmd); + return io.sourcing.stack[cmd].pop(); + } + function push(cmd, value) { + util.assert(io.sourcing, "Invalid use of conditional"); + if (arguments.length < 2) + value = io.sourcing.noExecute; + io.sourcing.stack = io.sourcing.stack || {}; + io.sourcing.stack[cmd] = (io.sourcing.stack[cmd] || []).concat([value]) + } + + commands.add(["if"], + "Execute commands until the next :elseif, :else, or :endif only if the argument returns true", + function (args) { io.sourcing.noExecute = !dactyl.userEval(args[0]); }, + { + always: function (args) { push("if") }, + argCount: "1", + literal: 0 + }); + commands.add(["elsei[f]", "elif"], + "Execute commands until the next :elseif, :else, or :endif only if the argument returns true", + function (args) {}, + { + always: function (args) { + checkStack("if"); + io.sourcing.noExecute = io.sourcing.stack.if.slice(-1)[0] || + !io.sourcing.noExecute || !dactyl.userEval(args[0]); + }, + argCount: "1", + literal: 0 + }); + commands.add(["el[se]"], + "Execute commands until the next :endif only if the previous conditionals were not executed", + function (args) {}, + { + always: function (args) { + checkStack("if"); + io.sourcing.noExecute = io.sourcing.stack.if.slice(-1)[0] || + !io.sourcing.noExecute; + }, + argCount: "0" + }); + commands.add(["en[dif]", "fi"], + "Ends a string of :if/:elseif/:else conditionals", + function (args) {}, + { + always: function (args) { io.sourcing.noExecute = pop("if") }, + argCount: "0" + }); + commands.add(["y[ank]"], "Yanks the output of the given command to the clipboard", function (args) { diff --git a/common/locale/en-US/eval.xml b/common/locale/en-US/eval.xml index b6c0912e..3ff5216b 100644 --- a/common/locale/en-US/eval.xml +++ b/common/locale/en-US/eval.xml @@ -24,6 +24,8 @@ along with paren matching and syntax error highlighting.

+

JavaScript evaluation

+ :ec :echo :echo expr @@ -134,6 +136,8 @@ +

Global Variables

+ :let :let var-name [+-.]= expr1 @@ -166,6 +170,55 @@ +

Conditionals

+ + + :if + :if expr + +

+ Execute commands until the next :elseif, :else, + or :endif only if the JavaScript expression expr + evaluates to a true value. +

+
+
+ + + :endif :en :fi + :endif + +

+ Ends a string of :if/:elseif/:else + conditionals. +

+
+
+ + + + :elseif :elsei :elif + :elseif expr + +

+ Execute commands until the next :elseif, :else, + or :endif only if the JavaScript expression expr + evaluates to a true value. +

+
+
+ + + :else :el + :else + +

+ Execute commands until the next :endif only if the + previous conditionals were not executed. +

+
+
+ diff --git a/common/locale/en-US/index.xml b/common/locale/en-US/index.xml index fa87d917..35d45308 100644 --- a/common/locale/en-US/index.xml +++ b/common/locale/en-US/index.xml @@ -242,7 +242,10 @@ This file contains a list of all available commands, mappings and options.
:echo
Echo the expression
:echoerr
Echo the expression as an error message
:echomsg
Echo the expression as an informational message
+
:else
Execute commands until the next :endif only if the previous conditionals were not executed
+
:elseif
Execute commands until the next :elseif, :else, or :endif only if the argument returns true
:emenu
Execute the specified menu item from the command line
+
:endif
Ends a string of :if/:elseif/:else conditionals
:execute
Execute the argument as an Ex command
:extadd
Install an extension
:extdelete
Uninstall an extension
@@ -262,6 +265,7 @@ This file contains a list of all available commands, mappings and options.
:history
Show recently visited URLs
:iabbrev
Abbreviate a key sequence in Insert mode
:iabclear
Remove all abbreviations in Insert mode
+
:if
Execute commands until the next :elseif, :else, or :endif only if the argument returns true
:imap
Map a key sequence in Insert mode
:imapclear
Remove all mappings in Insert mode
:inoremap
Map a key sequence without remapping keys in Insert mode
diff --git a/common/locale/en-US/repeat.xml b/common/locale/en-US/repeat.xml index 8875b65e..90a04ab4 100644 --- a/common/locale/en-US/repeat.xml +++ b/common/locale/en-US/repeat.xml @@ -169,6 +169,8 @@ on a single line, you can use

+

See also ex-scripts below.

+ :js <<EOF var hello = function () { alert(Hello world); @@ -228,6 +230,54 @@ +

Ex Command Scripts

+ +

+ Ex command scripts are similar to both entering commands on the + command line and to Vim + scripts, but with some notable differences. +

+ +

+ Commands in Ex command scripts can span multiple lines by + prefixing the second and further lines with a \ + character. For instance, the following all define commands whose + definitions span multiple lines. +

+ +:command! foo + \ -description A command that frobs bars + \ :javascript frob(content.bar) + +:style -name foo + \ foobar.com + \ p:first-line { font-variant: small-caps; } + \ div#side-bar > :first-child { display: none; } + +:command do-some-stuff + \ -description A command does some stuff in JavaScript + \ :javascript <<EOF + \ window.do(some); + \ window.do(stuff); + \EOF + +:command do-some-stuff + \ -description A command does some stuff in JavaScript + \ :javascript + \\ window.do(some); + \\ window.do(stuff); + +

+ Lines may be commented out by prefixing them with a " + character. +

+ + " This is a comment + foo bar " This is a comment + This is not a comment + foo bar This is not a cumment + +

Profiling

diff --git a/pentadactyl/NEWS b/pentadactyl/NEWS index f9aace11..2d3bbd98 100644 --- a/pentadactyl/NEWS +++ b/pentadactyl/NEWS @@ -78,6 +78,7 @@ * Added "passwords" and "venkman" dialogs to :dialog. * Added :extupdate command. * Replaced 'focuscontent' with 'strictfocus'. + * Add :if/:elseif/:else/:endif conditionals. * Changed 'urlseparator' default value to '|'. * Added 'wildanchor' option. * Added -javascript option to :abbrev and :map.