You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ch...@apache.org on 2013/07/22 08:58:04 UTC

svn commit: r1505607 [3/3] - in /felix/trunk/webconsole-plugins/script-console: ./ src/ src/main/ src/main/appended-resources/ src/main/appended-resources/META-INF/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/fe...

Added: felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/codemirror/mode/groovy/groovy.js
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/codemirror/mode/groovy/groovy.js?rev=1505607&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/codemirror/mode/groovy/groovy.js (added)
+++ felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/codemirror/mode/groovy/groovy.js Mon Jul 22 06:58:03 2013
@@ -0,0 +1,210 @@
+CodeMirror.defineMode("groovy", function(config) {
+  function words(str) {
+    var obj = {}, words = str.split(" ");
+    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+    return obj;
+  }
+  var keywords = words(
+    "abstract as assert boolean break byte case catch char class const continue def default " +
+    "do double else enum extends final finally float for goto if implements import in " +
+    "instanceof int interface long native new package private protected public return " +
+    "short static strictfp super switch synchronized threadsafe throw throws transient " +
+    "try void volatile while");
+  var blockKeywords = words("catch class do else finally for if switch try while enum interface def");
+  var atoms = words("null true false this");
+
+  var curPunc;
+  function tokenBase(stream, state) {
+    var ch = stream.next();
+    if (ch == '"' || ch == "'") {
+      return startString(ch, stream, state);
+    }
+    if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
+      curPunc = ch;
+      return null;
+    }
+    if (/\d/.test(ch)) {
+      stream.eatWhile(/[\w\.]/);
+      if (stream.eat(/eE/)) { stream.eat(/\+\-/); stream.eatWhile(/\d/); }
+      return "number";
+    }
+    if (ch == "/") {
+      if (stream.eat("*")) {
+        state.tokenize.push(tokenComment);
+        return tokenComment(stream, state);
+      }
+      if (stream.eat("/")) {
+        stream.skipToEnd();
+        return "comment";
+      }
+      if (expectExpression(state.lastToken)) {
+        return startString(ch, stream, state);
+      }
+    }
+    if (ch == "-" && stream.eat(">")) {
+      curPunc = "->";
+      return null;
+    }
+    if (/[+\-*&%=<>!?|\/~]/.test(ch)) {
+      stream.eatWhile(/[+\-*&%=<>|~]/);
+      return "operator";
+    }
+    stream.eatWhile(/[\w\$_]/);
+    if (ch == "@") { stream.eatWhile(/[\w\$_\.]/); return "meta"; }
+    if (state.lastToken == ".") return "property";
+    if (stream.eat(":")) { curPunc = "proplabel"; return "property"; }
+    var cur = stream.current();
+    if (atoms.propertyIsEnumerable(cur)) { return "atom"; }
+    if (keywords.propertyIsEnumerable(cur)) {
+      if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
+      return "keyword";
+    }
+    return "variable";
+  }
+  tokenBase.isBase = true;
+
+  function startString(quote, stream, state) {
+    var tripleQuoted = false;
+    if (quote != "/" && stream.eat(quote)) {
+      if (stream.eat(quote)) tripleQuoted = true;
+      else return "string";
+    }
+    function t(stream, state) {
+      var escaped = false, next, end = !tripleQuoted;
+      while ((next = stream.next()) != null) {
+        if (next == quote && !escaped) {
+          if (!tripleQuoted) { break; }
+          if (stream.match(quote + quote)) { end = true; break; }
+        }
+        if (quote == '"' && next == "$" && !escaped && stream.eat("{")) {
+          state.tokenize.push(tokenBaseUntilBrace());
+          return "string";
+        }
+        escaped = !escaped && next == "\\";
+      }
+      if (end) state.tokenize.pop();
+      return "string";
+    }
+    state.tokenize.push(t);
+    return t(stream, state);
+  }
+
+  function tokenBaseUntilBrace() {
+    var depth = 1;
+    function t(stream, state) {
+      if (stream.peek() == "}") {
+        depth--;
+        if (depth == 0) {
+          state.tokenize.pop();
+          return state.tokenize[state.tokenize.length-1](stream, state);
+        }
+      } else if (stream.peek() == "{") {
+        depth++;
+      }
+      return tokenBase(stream, state);
+    }
+    t.isBase = true;
+    return t;
+  }
+
+  function tokenComment(stream, state) {
+    var maybeEnd = false, ch;
+    while (ch = stream.next()) {
+      if (ch == "/" && maybeEnd) {
+        state.tokenize.pop();
+        break;
+      }
+      maybeEnd = (ch == "*");
+    }
+    return "comment";
+  }
+
+  function expectExpression(last) {
+    return !last || last == "operator" || last == "->" || /[\.\[\{\(,;:]/.test(last) ||
+      last == "newstatement" || last == "keyword" || last == "proplabel";
+  }
+
+  function Context(indented, column, type, align, prev) {
+    this.indented = indented;
+    this.column = column;
+    this.type = type;
+    this.align = align;
+    this.prev = prev;
+  }
+  function pushContext(state, col, type) {
+    return state.context = new Context(state.indented, col, type, null, state.context);
+  }
+  function popContext(state) {
+    var t = state.context.type;
+    if (t == ")" || t == "]" || t == "}")
+      state.indented = state.context.indented;
+    return state.context = state.context.prev;
+  }
+
+  // Interface
+
+  return {
+    startState: function(basecolumn) {
+      return {
+        tokenize: [tokenBase],
+        context: new Context((basecolumn || 0) - config.indentUnit, 0, "top", false),
+        indented: 0,
+        startOfLine: true,
+        lastToken: null
+      };
+    },
+
+    token: function(stream, state) {
+      var ctx = state.context;
+      if (stream.sol()) {
+        if (ctx.align == null) ctx.align = false;
+        state.indented = stream.indentation();
+        state.startOfLine = true;
+        // Automatic semicolon insertion
+        if (ctx.type == "statement" && !expectExpression(state.lastToken)) {
+          popContext(state); ctx = state.context;
+        }
+      }
+      if (stream.eatSpace()) return null;
+      curPunc = null;
+      var style = state.tokenize[state.tokenize.length-1](stream, state);
+      if (style == "comment") return style;
+      if (ctx.align == null) ctx.align = true;
+
+      if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
+      // Handle indentation for {x -> \n ... }
+      else if (curPunc == "->" && ctx.type == "statement" && ctx.prev.type == "}") {
+        popContext(state);
+        state.context.align = false;
+      }
+      else if (curPunc == "{") pushContext(state, stream.column(), "}");
+      else if (curPunc == "[") pushContext(state, stream.column(), "]");
+      else if (curPunc == "(") pushContext(state, stream.column(), ")");
+      else if (curPunc == "}") {
+        while (ctx.type == "statement") ctx = popContext(state);
+        if (ctx.type == "}") ctx = popContext(state);
+        while (ctx.type == "statement") ctx = popContext(state);
+      }
+      else if (curPunc == ctx.type) popContext(state);
+      else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
+        pushContext(state, stream.column(), "statement");
+      state.startOfLine = false;
+      state.lastToken = curPunc || style;
+      return style;
+    },
+
+    indent: function(state, textAfter) {
+      if (!state.tokenize[state.tokenize.length-1].isBase) return 0;
+      var firstChar = textAfter && textAfter.charAt(0), ctx = state.context;
+      if (ctx.type == "statement" && !expectExpression(state.lastToken)) ctx = ctx.prev;
+      var closing = firstChar == ctx.type;
+      if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : config.indentUnit);
+      else if (ctx.align) return ctx.column + (closing ? 0 : 1);
+      else return ctx.indented + (closing ? 0 : config.indentUnit);
+    },
+
+    electricChars: "{}"
+  };
+});
+
+CodeMirror.defineMIME("text/x-groovy", "groovy");

Added: felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/codemirror/mode/javascript/javascript.js
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/codemirror/mode/javascript/javascript.js?rev=1505607&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/codemirror/mode/javascript/javascript.js (added)
+++ felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/codemirror/mode/javascript/javascript.js Mon Jul 22 06:58:03 2013
@@ -0,0 +1,476 @@
+// TODO actually recognize syntax of TypeScript constructs
+
+CodeMirror.defineMode("javascript", function(config, parserConfig) {
+  var indentUnit = config.indentUnit;
+  var statementIndent = parserConfig.statementIndent;
+  var jsonMode = parserConfig.json;
+  var isTS = parserConfig.typescript;
+
+  // Tokenizer
+
+  var keywords = function(){
+    function kw(type) {return {type: type, style: "keyword"};}
+    var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
+    var operator = kw("operator"), atom = {type: "atom", style: "atom"};
+
+    var jsKeywords = {
+      "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
+      "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
+      "var": kw("var"), "const": kw("var"), "let": kw("var"),
+      "function": kw("function"), "catch": kw("catch"),
+      "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
+      "in": operator, "typeof": operator, "instanceof": operator,
+      "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
+      "this": kw("this")
+    };
+
+    // Extend the 'normal' keywords with the TypeScript language extensions
+    if (isTS) {
+      var type = {type: "variable", style: "variable-3"};
+      var tsKeywords = {
+        // object-like things
+        "interface": kw("interface"),
+        "class": kw("class"),
+        "extends": kw("extends"),
+        "constructor": kw("constructor"),
+
+        // scope modifiers
+        "public": kw("public"),
+        "private": kw("private"),
+        "protected": kw("protected"),
+        "static": kw("static"),
+
+        "super": kw("super"),
+
+        // types
+        "string": type, "number": type, "bool": type, "any": type
+      };
+
+      for (var attr in tsKeywords) {
+        jsKeywords[attr] = tsKeywords[attr];
+      }
+    }
+
+    return jsKeywords;
+  }();
+
+  var isOperatorChar = /[+\-*&%=<>!?|~^]/;
+
+  function chain(stream, state, f) {
+    state.tokenize = f;
+    return f(stream, state);
+  }
+
+  function nextUntilUnescaped(stream, end) {
+    var escaped = false, next;
+    while ((next = stream.next()) != null) {
+      if (next == end && !escaped)
+        return false;
+      escaped = !escaped && next == "\\";
+    }
+    return escaped;
+  }
+
+  // Used as scratch variables to communicate multiple values without
+  // consing up tons of objects.
+  var type, content;
+  function ret(tp, style, cont) {
+    type = tp; content = cont;
+    return style;
+  }
+
+  function jsTokenBase(stream, state) {
+    var ch = stream.next();
+    if (ch == '"' || ch == "'")
+      return chain(stream, state, jsTokenString(ch));
+    else if (/[\[\]{}\(\),;\:\.]/.test(ch))
+      return ret(ch);
+    else if (ch == "0" && stream.eat(/x/i)) {
+      stream.eatWhile(/[\da-f]/i);
+      return ret("number", "number");
+    }
+    else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
+      stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
+      return ret("number", "number");
+    }
+    else if (ch == "/") {
+      if (stream.eat("*")) {
+        return chain(stream, state, jsTokenComment);
+      }
+      else if (stream.eat("/")) {
+        stream.skipToEnd();
+        return ret("comment", "comment");
+      }
+      else if (state.lastType == "operator" || state.lastType == "keyword c" ||
+               /^[\[{}\(,;:]$/.test(state.lastType)) {
+        nextUntilUnescaped(stream, "/");
+        stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
+        return ret("regexp", "string-2");
+      }
+      else {
+        stream.eatWhile(isOperatorChar);
+        return ret("operator", null, stream.current());
+      }
+    }
+    else if (ch == "#") {
+      stream.skipToEnd();
+      return ret("error", "error");
+    }
+    else if (isOperatorChar.test(ch)) {
+      stream.eatWhile(isOperatorChar);
+      return ret("operator", null, stream.current());
+    }
+    else {
+      stream.eatWhile(/[\w\$_]/);
+      var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
+      return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
+                     ret("variable", "variable", word);
+    }
+  }
+
+  function jsTokenString(quote) {
+    return function(stream, state) {
+      if (!nextUntilUnescaped(stream, quote))
+        state.tokenize = jsTokenBase;
+      return ret("string", "string");
+    };
+  }
+
+  function jsTokenComment(stream, state) {
+    var maybeEnd = false, ch;
+    while (ch = stream.next()) {
+      if (ch == "/" && maybeEnd) {
+        state.tokenize = jsTokenBase;
+        break;
+      }
+      maybeEnd = (ch == "*");
+    }
+    return ret("comment", "comment");
+  }
+
+  // Parser
+
+  var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true};
+
+  function JSLexical(indented, column, type, align, prev, info) {
+    this.indented = indented;
+    this.column = column;
+    this.type = type;
+    this.prev = prev;
+    this.info = info;
+    if (align != null) this.align = align;
+  }
+
+  function inScope(state, varname) {
+    for (var v = state.localVars; v; v = v.next)
+      if (v.name == varname) return true;
+  }
+
+  function parseJS(state, style, type, content, stream) {
+    var cc = state.cc;
+    // Communicate our context to the combinators.
+    // (Less wasteful than consing up a hundred closures on every call.)
+    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
+
+    if (!state.lexical.hasOwnProperty("align"))
+      state.lexical.align = true;
+
+    while(true) {
+      var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
+      if (combinator(type, content)) {
+        while(cc.length && cc[cc.length - 1].lex)
+          cc.pop()();
+        if (cx.marked) return cx.marked;
+        if (type == "variable" && inScope(state, content)) return "variable-2";
+        return style;
+      }
+    }
+  }
+
+  // Combinator utils
+
+  var cx = {state: null, column: null, marked: null, cc: null};
+  function pass() {
+    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
+  }
+  function cont() {
+    pass.apply(null, arguments);
+    return true;
+  }
+  function register(varname) {
+    function inList(list) {
+      for (var v = list; v; v = v.next)
+        if (v.name == varname) return true;
+      return false;
+    }
+    var state = cx.state;
+    if (state.context) {
+      cx.marked = "def";
+      if (inList(state.localVars)) return;
+      state.localVars = {name: varname, next: state.localVars};
+    } else {
+      if (inList(state.globalVars)) return;
+      state.globalVars = {name: varname, next: state.globalVars};
+    }
+  }
+
+  // Combinators
+
+  var defaultVars = {name: "this", next: {name: "arguments"}};
+  function pushcontext() {
+    cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
+    cx.state.localVars = defaultVars;
+  }
+  function popcontext() {
+    cx.state.localVars = cx.state.context.vars;
+    cx.state.context = cx.state.context.prev;
+  }
+  function pushlex(type, info) {
+    var result = function() {
+      var state = cx.state, indent = state.indented;
+      if (state.lexical.type == "stat") indent = state.lexical.indented;
+      state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
+    };
+    result.lex = true;
+    return result;
+  }
+  function poplex() {
+    var state = cx.state;
+    if (state.lexical.prev) {
+      if (state.lexical.type == ")")
+        state.indented = state.lexical.indented;
+      state.lexical = state.lexical.prev;
+    }
+  }
+  poplex.lex = true;
+
+  function expect(wanted) {
+    return function(type) {
+      if (type == wanted) return cont();
+      else if (wanted == ";") return pass();
+      else return cont(arguments.callee);
+    };
+  }
+
+  function statement(type) {
+    if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
+    if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
+    if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
+    if (type == "{") return cont(pushlex("}"), block, poplex);
+    if (type == ";") return cont();
+    if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse(cx.state.indented));
+    if (type == "function") return cont(functiondef);
+    if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
+                                      poplex, statement, poplex);
+    if (type == "variable") return cont(pushlex("stat"), maybelabel);
+    if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
+                                         block, poplex, poplex);
+    if (type == "case") return cont(expression, expect(":"));
+    if (type == "default") return cont(expect(":"));
+    if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
+                                        statement, poplex, popcontext);
+    return pass(pushlex("stat"), expression, expect(";"), poplex);
+  }
+  function expression(type) {
+    return expressionInner(type, false);
+  }
+  function expressionNoComma(type) {
+    return expressionInner(type, true);
+  }
+  function expressionInner(type, noComma) {
+    var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
+    if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
+    if (type == "function") return cont(functiondef);
+    if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
+    if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
+    if (type == "operator") return cont(noComma ? expressionNoComma : expression);
+    if (type == "[") return cont(pushlex("]"), commasep(expressionNoComma, "]"), poplex, maybeop);
+    if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeop);
+    return cont();
+  }
+  function maybeexpression(type) {
+    if (type.match(/[;\}\)\],]/)) return pass();
+    return pass(expression);
+  }
+  function maybeexpressionNoComma(type) {
+    if (type.match(/[;\}\)\],]/)) return pass();
+    return pass(expressionNoComma);
+  }
+
+  function maybeoperatorComma(type, value) {
+    if (type == ",") return cont(expression);
+    return maybeoperatorNoComma(type, value, maybeoperatorComma);
+  }
+  function maybeoperatorNoComma(type, value, me) {
+    if (!me) me = maybeoperatorNoComma;
+    if (type == "operator") {
+      if (/\+\+|--/.test(value)) return cont(me);
+      if (value == "?") return cont(expression, expect(":"), expression);
+      return cont(expression);
+    }
+    if (type == ";") return;
+    if (type == "(") return cont(pushlex(")", "call"), commasep(expressionNoComma, ")"), poplex, me);
+    if (type == ".") return cont(property, me);
+    if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, me);
+  }
+  function maybelabel(type) {
+    if (type == ":") return cont(poplex, statement);
+    return pass(maybeoperatorComma, expect(";"), poplex);
+  }
+  function property(type) {
+    if (type == "variable") {cx.marked = "property"; return cont();}
+  }
+  function objprop(type, value) {
+    if (type == "variable") {
+      cx.marked = "property";
+      if (value == "get" || value == "set") return cont(getterSetter);
+    } else if (type == "number" || type == "string") {
+      cx.marked = type + " property";
+    }
+    if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expressionNoComma);
+  }
+  function getterSetter(type) {
+    if (type == ":") return cont(expression);
+    if (type != "variable") return cont(expect(":"), expression);
+    cx.marked = "property";
+    return cont(functiondef);
+  }
+  function commasep(what, end) {
+    function proceed(type) {
+      if (type == ",") {
+        var lex = cx.state.lexical;
+        if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
+        return cont(what, proceed);
+      }
+      if (type == end) return cont();
+      return cont(expect(end));
+    }
+    return function(type) {
+      if (type == end) return cont();
+      else return pass(what, proceed);
+    };
+  }
+  function block(type) {
+    if (type == "}") return cont();
+    return pass(statement, block);
+  }
+  function maybetype(type) {
+    if (type == ":") return cont(typedef);
+    return pass();
+  }
+  function typedef(type) {
+    if (type == "variable"){cx.marked = "variable-3"; return cont();}
+    return pass();
+  }
+  function vardef1(type, value) {
+    if (type == "variable") {
+      register(value);
+      return isTS ? cont(maybetype, vardef2) : cont(vardef2);
+    }
+    return pass();
+  }
+  function vardef2(type, value) {
+    if (value == "=") return cont(expressionNoComma, vardef2);
+    if (type == ",") return cont(vardef1);
+  }
+  function maybeelse(indent) {
+    return function(type, value) {
+      if (type == "keyword b" && value == "else") {
+        cx.state.lexical = new JSLexical(indent, 0, "form", null, cx.state.lexical);
+        return cont(statement, poplex);
+      }
+      return pass();
+    };
+  }
+  function forspec1(type) {
+    if (type == "var") return cont(vardef1, expect(";"), forspec2);
+    if (type == ";") return cont(forspec2);
+    if (type == "variable") return cont(formaybein);
+    return pass(expression, expect(";"), forspec2);
+  }
+  function formaybein(_type, value) {
+    if (value == "in") return cont(expression);
+    return cont(maybeoperatorComma, forspec2);
+  }
+  function forspec2(type, value) {
+    if (type == ";") return cont(forspec3);
+    if (value == "in") return cont(expression);
+    return pass(expression, expect(";"), forspec3);
+  }
+  function forspec3(type) {
+    if (type != ")") cont(expression);
+  }
+  function functiondef(type, value) {
+    if (type == "variable") {register(value); return cont(functiondef);}
+    if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
+  }
+  function funarg(type, value) {
+    if (type == "variable") {register(value); return isTS ? cont(maybetype) : cont();}
+  }
+
+  // Interface
+
+  return {
+    startState: function(basecolumn) {
+      return {
+        tokenize: jsTokenBase,
+        lastType: null,
+        cc: [],
+        lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
+        localVars: parserConfig.localVars,
+        globalVars: parserConfig.globalVars,
+        context: parserConfig.localVars && {vars: parserConfig.localVars},
+        indented: 0
+      };
+    },
+
+    token: function(stream, state) {
+      if (stream.sol()) {
+        if (!state.lexical.hasOwnProperty("align"))
+          state.lexical.align = false;
+        state.indented = stream.indentation();
+      }
+      if (state.tokenize != jsTokenComment && stream.eatSpace()) return null;
+      var style = state.tokenize(stream, state);
+      if (type == "comment") return style;
+      state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
+      return parseJS(state, style, type, content, stream);
+    },
+
+    indent: function(state, textAfter) {
+      if (state.tokenize == jsTokenComment) return CodeMirror.Pass;
+      if (state.tokenize != jsTokenBase) return 0;
+      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
+      if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
+      if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
+        lexical = lexical.prev;
+      var type = lexical.type, closing = firstChar == type;
+
+      if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0);
+      else if (type == "form" && firstChar == "{") return lexical.indented;
+      else if (type == "form") return lexical.indented + indentUnit;
+      else if (type == "stat")
+        return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? statementIndent || indentUnit : 0);
+      else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
+        return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
+      else if (lexical.align) return lexical.column + (closing ? 0 : 1);
+      else return lexical.indented + (closing ? 0 : indentUnit);
+    },
+
+    electricChars: ":{}",
+    blockCommentStart: jsonMode ? null : "/*",
+    blockCommentEnd: jsonMode ? null : "*/",
+    lineComment: jsonMode ? null : "//",
+
+    jsonMode: jsonMode
+  };
+});
+
+CodeMirror.defineMIME("text/javascript", "javascript");
+CodeMirror.defineMIME("text/ecmascript", "javascript");
+CodeMirror.defineMIME("application/javascript", "javascript");
+CodeMirror.defineMIME("application/ecmascript", "javascript");
+CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
+CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
+CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
+CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });

Added: felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/script-console.css
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/script-console.css?rev=1505607&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/script-console.css (added)
+++ felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/script-console.css Mon Jul 22 06:58:03 2013
@@ -0,0 +1,4 @@
+.CodeMirror {
+    /*border-top: 1px solid black;*/
+    border-bottom: 1px solid black;
+}
\ No newline at end of file

Added: felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/script-console.js
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/script-console.js?rev=1505607&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/script-console.js (added)
+++ felix/trunk/webconsole-plugins/script-console/src/main/resources/res/ui/script-console.js Mon Jul 22 06:58:03 2013
@@ -0,0 +1,104 @@
+//Codemirror editor
+var inputEditor
+var outputEditor
+
+function sendData(url, data) {
+    $.ajax({
+        type:"POST",
+        url:url,
+        data:data,
+//        dataType:"json",
+        timeout:30000, //In millis
+        beforeSend:function () {
+            $('#ajaxSpinner').show();
+        },
+        /* error: function() {
+         $('#status').text('Update failed�try again.').slideDown('slow');
+         },*/
+        complete:function () {
+            $('#ajaxSpinner').hide();
+        },
+        success:function (data) {
+            renderData(data)
+        }
+    });
+}
+
+function renderData(data){
+    $('#code-output').show();
+    outputEditor.setValue(data)
+}
+
+function setUpCodeMirror() {
+    CodeMirror.modeURL = pluginRoot + "/res/ui/codemirror/mode/%N/%N.js";
+    inputEditor = CodeMirror.fromTextArea(document.getElementById("code"), {
+        lineNumbers:true,
+        extraKeys: {
+            'Ctrl-Q':clearOutput,
+            'Ctrl-F9':executeScript
+        }
+    });
+    outputEditor = CodeMirror.fromTextArea(document.getElementById("result"), {
+            lineNumbers:true,
+            readOnly:"nocursor"
+        });
+}
+
+function updateWithOption(opt){
+    setLangMode(inputEditor,getProp(opt,'langMode'))
+    $('[name=lang]').val(opt.val())
+}
+
+function setLangMode(editor, modeName) {
+    if(!modeName){
+        modeName = "text/plain"
+    }else{
+        CodeMirror.autoLoadMode(inputEditor, modeName);
+    }
+    editor.setOption("mode", modeName);
+}
+
+function getProp(obj,propName){
+    if(obj != null){
+        return obj.prop ?  obj.prop(propName) : obj.attr(propName)
+    }
+}
+
+function setUpLangOptions() {
+    var codeLang = $('#codeLang')
+    var options = getProp(codeLang,'options');
+    codeLang.empty()
+
+    for(var i in scriptConfig){
+        var config = scriptConfig[i]
+        var opt = new Option(config.langName,config.langCode);
+        if(config.mode){
+            opt.langMode = config.mode;
+        }
+        options[options.length] = opt
+    }
+    codeLang.change(function(){
+        var opt = $(this).find(":selected");
+        updateWithOption(opt)
+    });
+
+    codeLang.find('option:eq(0)').attr('selected','selected')
+    updateWithOption($(options[0]))
+}
+
+function executeScript(){
+    inputEditor.save() //Copy the contents to textarea form field
+    sendData(pluginRoot, $("#consoleForm").serialize());
+}
+
+function clearOutput(){
+    outputEditor.setValue('')
+}
+
+$(document).ready(function () {
+    $("#executeButton").click(executeScript);
+    $('#ajaxSpinner').hide();
+    $('#code-output').hide();
+    setUpCodeMirror();
+    setUpLangOptions();
+});

Added: felix/trunk/webconsole-plugins/script-console/src/main/resources/templates/script-console.html
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/script-console/src/main/resources/templates/script-console.html?rev=1505607&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/script-console/src/main/resources/templates/script-console.html (added)
+++ felix/trunk/webconsole-plugins/script-console/src/main/resources/templates/script-console.html Mon Jul 22 06:58:03 2013
@@ -0,0 +1,34 @@
+<script type="text/javascript" src="${pluginRoot}/res/ui/codemirror/lib/codemirror.js"></script>
+<script type="text/javascript" src="${pluginRoot}/res/ui/codemirror/addon/runmode/runmode.js"></script>
+<script type="text/javascript" src="${pluginRoot}/res/ui/codemirror/addon/mode/loadmode.js"></script>
+<script type="text/javascript" src="${pluginRoot}/res/ui/script-console.js"></script>
+<script type="text/javascript">
+// <![CDATA[
+var scriptConfig = ${__scriptConfig__};
+// ]]>
+</script>
+
+<!-- status line -->
+<p class="statline">&nbsp;</p>
+<div class="ui-widget-header ">
+    <img id="ajaxSpinner" src="${appRoot}/res/imgs/loading.gif" tile="Working..." />
+    <button type="button" id="executeButton">${console.execute}</button>
+    <button type="button" id="langButton">${console.lang}</button>
+    <select id="codeLang">
+        <option></option>
+    </select>
+</div>
+<div id="splitter" >
+    <div id="code-input">
+        <form method="post" action="${pluginRoot}" id="consoleForm">
+            <textarea id="code" name="code"
+                      style="width: 90%; height: 7em; "></textarea>
+            <input type="hidden" name="client" value="webconsole" />
+            <input type="hidden" name="lang" value="" />
+        </form>
+    </div>
+    <div id="code-output">
+        <textarea id="result" style="width: 90%;" readonly="yes"></textarea>
+    </div>
+</div>
+

Added: felix/trunk/webconsole-plugins/script-console/src/test/java/org/apache/felix/webconsole/plugins/scriptconsole/integration/ITScriptConsolePlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/script-console/src/test/java/org/apache/felix/webconsole/plugins/scriptconsole/integration/ITScriptConsolePlugin.java?rev=1505607&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/script-console/src/test/java/org/apache/felix/webconsole/plugins/scriptconsole/integration/ITScriptConsolePlugin.java (added)
+++ felix/trunk/webconsole-plugins/script-console/src/test/java/org/apache/felix/webconsole/plugins/scriptconsole/integration/ITScriptConsolePlugin.java Mon Jul 22 06:58:03 2013
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.webconsole.plugins.scriptconsole.integration;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.entity.mime.MultipartEntity;
+import org.apache.http.entity.mime.content.ContentBody;
+import org.apache.http.entity.mime.content.StringBody;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.sling.testing.tools.http.RequestBuilder;
+import org.apache.sling.testing.tools.http.RequestExecutor;
+import org.junit.Test;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ITScriptConsolePlugin
+{
+    private DefaultHttpClient httpClient = new DefaultHttpClient();
+    private RequestExecutor executor = new RequestExecutor(httpClient);
+
+    @Test
+    public void testScriptExecution() throws Exception
+    {
+          //Somehow multipart data based invocation does not work in with old webconsole
+//        execute(new InputStreamBody(getClass().getResourceAsStream("/test.groovy"),
+//            "test.groovy"));
+//        execute(new StringBody("def a = 2+2; assert a == 4;"));
+        InputStream is = getClass().getResourceAsStream("/test.groovy");
+        try{
+            execute2(IOUtils.toString(is, "utf-8"));
+        }finally {
+            IOUtils.closeQuietly(is);
+        }
+        execute2("def a = 2+2; assert a == 4;");
+    }
+
+    private void execute(ContentBody code) throws Exception
+    {
+        RequestBuilder rb = new RequestBuilder(ServerConfiguration.getServerUrl());
+
+        final MultipartEntity entity = new MultipartEntity();
+        // Add Sling POST options
+        entity.addPart("lang", new StringBody("groovy"));
+        entity.addPart("code", code);
+        executor.execute(
+            rb.buildPostRequest("/system/console/sc").withEntity(entity).withCredentials(
+                    "admin", "admin")).assertStatus(200);
+    }
+
+    private void execute2(String code) throws Exception
+    {
+        RequestBuilder rb = new RequestBuilder(ServerConfiguration.getServerUrl());
+
+        List<NameValuePair> params = new ArrayList<NameValuePair>();
+        params.add(new BasicNameValuePair("lang","groovy"));
+        params.add(new BasicNameValuePair("code",code));
+
+        final HttpEntity entity = new UrlEncodedFormEntity(params);
+        // Add Sling POST options
+        executor.execute(
+                rb.buildPostRequest("/system/console/sc")
+                        .withEntity(entity)
+                        .withCredentials("admin", "admin"))
+                .assertStatus(200);
+    }
+
+}

Added: felix/trunk/webconsole-plugins/script-console/src/test/java/org/apache/felix/webconsole/plugins/scriptconsole/integration/ServerConfiguration.java
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/script-console/src/test/java/org/apache/felix/webconsole/plugins/scriptconsole/integration/ServerConfiguration.java?rev=1505607&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/script-console/src/test/java/org/apache/felix/webconsole/plugins/scriptconsole/integration/ServerConfiguration.java (added)
+++ felix/trunk/webconsole-plugins/script-console/src/test/java/org/apache/felix/webconsole/plugins/scriptconsole/integration/ServerConfiguration.java Mon Jul 22 06:58:03 2013
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.webconsole.plugins.scriptconsole.integration;
+
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.OptionUtils;
+
+import java.io.File;
+
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+public class ServerConfiguration
+{
+
+    // the name of the system property providing the bundle file to be installed and tested
+    protected static final String BUNDLE_JAR_SYS_PROP = "project.bundle.file";
+
+    // the name of the system property which captures the jococo coverage agent command
+    //if specified then agent would be specified otherwise ignored
+    protected static final String COVERAGE_COMMAND = "coverage.command";
+
+    //Name of the property for port of server
+    public static final String HTTP_PORT_PROP = "http.port";
+
+    public static final String HTTP_SERVER__URL_PROP = "serverUrl";
+
+    // the default bundle jar file name
+    protected static final String BUNDLE_JAR_DEFAULT = "target/scriptconsole.jar";
+
+    // the JVM option to set to enable remote debugging
+    @SuppressWarnings("UnusedDeclaration")
+    protected static final String DEBUG_VM_OPTION = "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=31313";
+
+    // the actual JVM option set, extensions may implement a static
+    // initializer overwriting this value to have the configuration()
+    // method include it when starting the OSGi framework JVM
+    protected static String paxRunnerVmOption = null;
+//    protected static String paxRunnerVmOption = DEBUG_VM_OPTION;
+
+    protected static String DEFAULT_PORT = "8080";
+
+    @Configuration
+    public Option[] config()
+    {
+        final String bundleFileName = System.getProperty(BUNDLE_JAR_SYS_PROP,
+            BUNDLE_JAR_DEFAULT);
+        final File bundleFile = new File(bundleFileName);
+        if (!bundleFile.canRead())
+        {
+            throw new IllegalArgumentException("Cannot read from bundle file "
+                + bundleFileName + " specified in the " + BUNDLE_JAR_SYS_PROP
+                + " system property");
+        }
+        Option[] base = options(
+                // the current project (the bundle under test)
+                CoreOptions.bundle(bundleFile.toURI().toString()),
+                mavenBundle("org.ops4j.pax.logging", "pax-logging-api", "1.7.0").startLevel(2),
+                mavenBundle("org.ops4j.pax.logging", "pax-logging-service", "1.7.0").startLevel(2),
+                mavenBundle("org.apache.felix", "org.apache.felix.configadmin").versionAsInProject(),
+                mavenBundle("org.apache.felix", "org.apache.felix.http.jetty").versionAsInProject(),
+                mavenBundle("org.apache.felix", "org.apache.felix.webconsole").versionAsInProject(),
+                mavenBundle("commons-io", "commons-io").versionAsInProject(),
+                wrappedBundle(mavenBundle("commons-fileupload", "commons-fileupload").versionAsInProject()),
+                wrappedBundle(mavenBundle("org.json", "json").versionAsInProject()),
+                mavenBundle("org.codehaus.groovy", "groovy-all", "2.1.0"),
+                frameworkProperty("osgi.clean").value("true"),
+//            systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"),
+                systemProperty("pax.exam.osgi.unresolved.fail").value("fail"),
+                systemProperty("org.osgi.service.http.port").value(getServerPort()),
+                cleanCaches(),
+                addCodeCoverageOption());
+        final Option vmOption = (paxRunnerVmOption != null) ? CoreOptions.vmOption(paxRunnerVmOption)
+            : null;
+        return OptionUtils.combine(base, vmOption);
+    }
+
+    private static String getServerPort()
+    {
+        return System.getProperty(HTTP_PORT_PROP, DEFAULT_PORT);
+    }
+
+    private Option addCodeCoverageOption()
+    {
+        String coverageCommand = System.getProperty(COVERAGE_COMMAND);
+        if (coverageCommand != null)
+        {
+            return CoreOptions.vmOption(coverageCommand);
+        }
+        return null;
+    }
+
+    public static String getServerUrl()
+    {
+        String serverUrl = System.getProperty(HTTP_SERVER__URL_PROP);
+        if (serverUrl != null)
+        {
+            return serverUrl;
+        }
+
+        return String.format("http://localhost:%s", getServerPort());
+    }
+}

Added: felix/trunk/webconsole-plugins/script-console/src/test/resources/test.groovy
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/script-console/src/test/resources/test.groovy?rev=1505607&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/script-console/src/test/resources/test.groovy (added)
+++ felix/trunk/webconsole-plugins/script-console/src/test/resources/test.groovy Mon Jul 22 06:58:03 2013
@@ -0,0 +1,2 @@
+def httpService  = osgi.getService(org.osgi.service.http.HttpService.class)
+assert httpService
\ No newline at end of file