ソースを参照

HUE-1729 [spark] Syntax highlighting for Scala and Java and hints

Added Java, Scala and Python autocomplete
Editor mode changes dinamycally now
Got rid of unused code
Enrico Berti 12 年 前
コミット
38b4cc5

+ 20 - 105
apps/spark/src/spark/templates/app.mako

@@ -511,10 +511,11 @@ ${ commonheader(None, "spark", user) | n,unicode }
 <script src="/spark/static/js/spark.ko.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/routie-0.3.0.min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/codemirror-3.11.js"></script>
-<script src="/static/js/clike.js"></script>
+<script src="/static/js/codemirror-clike.js"></script>
 <script src="/static/js/codemirror-python.js"></script>
 <script src="/static/js/codemirror-show-hint.js"></script>
-<script src="/static/js/codemirror-pig-hint.js"></script>
+<script src="/static/js/codemirror-python-hint.js"></script>
+<script src="/static/js/codemirror-clike-hint.js"></script>
 <script src="/beeswax/static/js/autocomplete.utils.js" type="text/javascript" charset="utf-8"></script>
 
 <link rel="stylesheet" href="/spark/static/css/spark.css">
@@ -556,9 +557,6 @@ ${ commonheader(None, "spark", user) | n,unicode }
   var viewModel = new SparkViewModel(appProperties);
   ko.applyBindings(viewModel);
 
-  var HIVE_AUTOCOMPLETE_BASE_URL = "${ autocomplete_base_url | n,unicode }";
-  var HIVE_AUTOCOMPLETE_FAILS_SILENTLY_ON = [503]; // error codes from beeswax/views.py - autocomplete
-
   var codeMirror;
 
   $(document).ready(function () {
@@ -571,88 +569,27 @@ ${ commonheader(None, "spark", user) | n,unicode }
     var logsAtEnd = true;
     var forceLogsAtEnd = false;
 
-    function storeVariables() {
-      CodeMirror.availableVariables = [];
-      var _val = codeMirror.getValue();
-      var _groups = _val.replace(/==/gi, "").split("=");
-      $.each(_groups, function (cnt, item) {
-        if (cnt < _groups.length - 1) {
-          var _blocks = $.trim(item).replace(/\n/gi, " ").split(" ");
-          CodeMirror.availableVariables.push(_blocks[_blocks.length - 1]);
-        }
-        if (item.toLowerCase().indexOf("split") > -1 && item.toLowerCase().indexOf("into") > -1) {
-          try {
-            var _split = item.substring(item.toLowerCase().indexOf("into"));
-            var _possibleVariables = $.trim(_split.substring(4, _split.indexOf(";"))).split(",");
-            $.each(_possibleVariables, function (icnt, iitem) {
-              if (iitem.toLowerCase().indexOf("if") > -1) {
-                CodeMirror.availableVariables.push($.trim(iitem).split(" ")[0]);
-              }
-            });
-          }
-          catch (e) {
-          }
-        }
-      });
-    }
-
-    var KLASS = "org.apache.hcatalog.pig.HCatLoader";
-
-    CodeMirror.onAutocomplete = function (data, from, to) {
-      if (CodeMirror.isHCatHint && data.indexOf(KLASS) > -1) {
-        codeMirror.replaceRange(" ", to, to);
-        codeMirror.setCursor(to);
-        CodeMirror.isHCatHint = false;
-        showHiveAutocomplete("default");
+    function getLanguageHint() {
+      var _hint = null;
+      switch (viewModel.currentScript().language()) {
+        case "java":
+          _hint = CodeMirror.javaHint;
+          break;
+        case "scala":
+          _hint = CodeMirror.scalaHint;
+          break;
+        case "python":
+          _hint = CodeMirror.pythonHint;
+          break;
       }
-    };
+      return _hint;
+    }
 
     CodeMirror.commands.autocomplete = function (cm) {
       $(document.body).on("contextmenu", function (e) {
         e.preventDefault(); // prevents native menu on FF for Mac from being shown
       });
-      storeVariables();
-      var _line = codeMirror.getLine(codeMirror.getCursor().line);
-      var _partial = _line.substring(0, codeMirror.getCursor().ch);
-      if (_partial.indexOf("'") > -1 && _partial.indexOf("'") == _partial.lastIndexOf("'")) {
-        CodeMirror.isHCatHint = false;
-        CodeMirror.isTable = false;
-        if (_partial.toLowerCase().indexOf("load") > -1 || _partial.toLowerCase().indexOf("into") > -1) {
-          var _path = _partial.substring(_partial.lastIndexOf("'") + 1);
-          var _autocompleteUrl = "/filebrowser/view";
-          if (_path.indexOf("/") == 0) {
-            _autocompleteUrl += _path.substr(0, _path.lastIndexOf("/"));
-          }
-          else if (_path.indexOf("/") > 0) {
-            _autocompleteUrl += USER_HOME + _path.substr(0, _path.lastIndexOf("/"));
-          }
-          else {
-            _autocompleteUrl += USER_HOME;
-          }
-          var _showHCatHint = false;
-          if (_line.indexOf(KLASS) == -1) {
-            if (_partial.indexOf("'") == _partial.length - 1) {
-              _showHCatHint = true;
-            }
-            showHdfsAutocomplete(_autocompleteUrl + "?format=json", _showHCatHint);
-          }
-          else {
-            var _db = _partial.substring(_partial.lastIndexOf("'") + 1);
-            if (_db.indexOf(".") > -1) {
-              showHiveAutocomplete(_db.substring(0, _db.length - 1));
-            }
-            else {
-              showHiveAutocomplete("default");
-            }
-          }
-        }
-      }
-      else {
-        CodeMirror.isPath = false;
-        CodeMirror.isTable = false;
-        CodeMirror.isHCatHint = false;
-        CodeMirror.showHint(cm, CodeMirror.pigHint);
-      }
+      CodeMirror.showHint(cm, getLanguageHint());
     }
     codeMirror = CodeMirror(function (elt) {
       scriptEditor.parentNode.replaceChild(elt, scriptEditor);
@@ -660,7 +597,7 @@ ${ commonheader(None, "spark", user) | n,unicode }
       value: scriptEditor.value,
       readOnly: false,
       lineNumbers: true,
-      mode: "text/x-" + viewModel.currentScript().language(), // TODO update to language dynamically
+      mode: "text/x-" + viewModel.currentScript().language(),
       extraKeys: {
         "Ctrl-Space": "autocomplete",
         "Ctrl-Enter": function () {
@@ -676,16 +613,6 @@ ${ commonheader(None, "spark", user) | n,unicode }
       },
       onKeyEvent: function (e, s) {
         if (s.type == "keyup") {
-          if (s.keyCode == 190) {
-            if (codeMirror.getValue().indexOf(KLASS) > -1) {
-              var _line = codeMirror.getLine(codeMirror.getCursor().line);
-              var _partial = _line.substring(0, codeMirror.getCursor().ch);
-              var _db = _partial.substring(_partial.lastIndexOf("'") + 1);
-              if (_partial.replace(/ /g, '').toUpperCase().indexOf("LOAD") == _partial.replace(/ /g, '').lastIndexOf("'") - 4) {
-                showHiveAutocomplete(_db.substring(0, _db.length - 1));
-              }
-            }
-          }
           if (s.keyCode == 191) {
             var _line = codeMirror.getLine(codeMirror.getCursor().line);
             var _partial = _line.substring(0, codeMirror.getCursor().ch);
@@ -719,24 +646,12 @@ ${ commonheader(None, "spark", user) | n,unicode }
           CodeMirror.isPath = true;
           CodeMirror.isHCatHint = showHCatHint;
           window.setTimeout(function () {
-            CodeMirror.showHint(codeMirror, CodeMirror.pigHint);
+            CodeMirror.showHint(codeMirror,  getLanguageHint());
           }, 100);  // timeout for IE8
         }
       });
     }
 
-    hac_getTables("default", function(){}); //preload tables for the default db
-
-    function showHiveAutocomplete(databaseName) {
-      CodeMirror.isPath = false;
-      CodeMirror.isTable = true;
-      CodeMirror.isHCatHint = false;
-      hac_getTables(databaseName, function (tables) {
-        CodeMirror.catalogTables = tables;
-        CodeMirror.showHint(codeMirror, CodeMirror.pigHint);
-      });
-    }
-
     codeMirror.on("focus", function () {
       if (codeMirror.getValue() == LABELS.NEW_SCRIPT_CONTENT[viewModel.currentScript().language()]) {
         codeMirror.setValue("");

+ 6 - 0
apps/spark/static/js/spark.ko.js

@@ -106,6 +106,12 @@ var SparkScript = function (sparkScript) {
   self.name.subscribe(function (name) {
     self.updateParentModel();
   });
+
+  self.language.subscribe(function (lang) {
+    if (typeof codeMirror != "undefined"){
+      codeMirror.setOption("mode", "text/x-" + lang);
+    }
+  });
 }
 
 var Workflow = function (wf) {

+ 122 - 0
desktop/core/static/js/codemirror-clike-hint.js

@@ -0,0 +1,122 @@
+(function () {
+  function forEach(arr, f) {
+    for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
+  }
+
+  function arrayContains(arr, item) {
+    if (!Array.prototype.indexOf) {
+      var i = arr.length;
+      while (i--) {
+        if (arr[i] === item) {
+          return true;
+        }
+      }
+      return false;
+    }
+    return arr.indexOf(item) != -1;
+  }
+
+  //Call this from outside environment to add more words to the list that might be specific to your component
+  //or taken from a current view model. They will show first in the list.
+  CodeMirror.addKeywords=function(keywords){
+    addedKeywords=keywords;
+  };
+
+  function scriptHint(editor, _keywords, getToken) {
+    // Find the token at the cursor
+    var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
+
+    // If it's not a 'word-style' token, ignore the token.
+    if (!/^[\w$_]*$/.test(token.string)) {
+        token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
+                         className: null};
+    }
+
+    if (!context) var context = [];
+    context.push(tprop);
+
+    var completionList = getCompletions(token, context, _keywords);
+
+    return {list: completionList,
+            from: CodeMirror.Pos(cur.line, token.start),
+            to: CodeMirror.Pos(cur.line, token.end)};
+  }
+
+  //Offers completion for C-sharp, C++, Java and Scala
+  function csharpHint(editor) {
+    return scriptHint(editor, getAllKeywords(csharpKeywords), function (e, cur) {return e.getTokenAt(cur);});
+    }
+  CodeMirror.csharpHint = csharpHint; // deprecated
+
+  function javaHint(editor) {
+    return scriptHint(editor, getAllKeywords(javaKeywords), function (e, cur) {return e.getTokenAt(cur);});
+    }
+  CodeMirror.javaHint = javaHint; // deprecated
+
+  function scalaHint(editor) {
+    return scriptHint(editor, getAllKeywords(scalaKeywords), function (e, cur) {return e.getTokenAt(cur);});
+    }
+  CodeMirror.scalaHint = scalaHint; // deprecated
+
+  var addedKeywords="";
+
+  //below are all the reserved words plus some of the more common method names
+  //but the list is no way pretending to be complete
+  var clikeKeywordString="abstract assert boolean break byte case catch char class const do default double else enum false "+
+  "finally for float goto if int interface long new null private protected public return short static string switch throw "+
+  "this try var void true using volatile while ";
+
+  var csharpKeywords="as await base bool checked continue decimal delegate event explicit extern finally fixed "+
+  "foreach implicit in internal is lock namespace object operator out override params readonly ref sbyte sealed sizeof stackalloc "+
+  "typeof uint ulong unchecked unsafe ushort virtual add alias ascending descending dynamic from get "+
+  "global group into join let orderby partial remove select set value var yield "+
+  "Byte Char Contains Count DateTime DateTimeOffset Decimal Double IndexOf "+
+  "LastIndexOf FirstIndexOf Format Substring Trim Length continue delete function Remove Split Replace with "+
+  "Range Guid Int16 Int32 Int64 Object SByte Single String TimeSpan UInt16 UInt32 UInt64 virtual";
+
+  var javaKeywords="concat extends final format implements import instanceof native "+
+  "package strictfp  super synchronized throws transient "+
+  "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable "+
+  "Compiler Double Exception Float Integer length Long Math Number Object Package Pair Process printl"+
+  "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String "+
+  "replace replaceAll replaceFirst substring toUpperCase toLowerCase trim"+
+  "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void";
+
+  var scalaKeywords="assume require print println printf readLine readBoolean readByte readShort " +
+  "readChar readInt readLong readFloat readDouble " +
+  "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
+  "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
+  "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
+  "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
+  "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: ";
+
+  function getAllKeywords(keywordString) {
+    var newKeywords=(addedKeywords+clikeKeywordString+keywordString).split(" ");
+    return newKeywords;
+  }
+
+  function getCompletions(token, context, _keywords) {
+    var found = [], start = token.string;
+    function maybeAdd(str) {
+     //searches with all lower case
+    if (str.indexOf(start.toLowerCase()) == 0 && !arrayContains(found, str)) found.push(str);
+    //searches with first letter upper case
+    if (str.indexOf(start.charAt(0).toUpperCase() + start.slice(1)) == 0 && !arrayContains(found, str)) found.push(str);
+    }
+
+  function gatherCompletions(_obj) {
+    forEach(_keywords,maybeAdd);
+    }
+
+    if (context) {
+      var obj = context.pop(), base;
+
+      if (obj.type== "variable")
+        base = obj.string;
+      while (base != null && context.length)
+        base = base[context.pop().string];
+      if (base != null) gatherCompletions(base);
+    }
+    return found;
+  }
+})();

+ 0 - 0
desktop/core/static/js/clike.js → desktop/core/static/js/codemirror-clike.js


+ 0 - 1
desktop/core/static/js/codemirror-python-hint.js

@@ -45,7 +45,6 @@
     return scriptHint(editor, pythonKeywordsU, function (e, cur) {return e.getTokenAt(cur);});
   }
   CodeMirror.pythonHint = pythonHint; // deprecated
-  CodeMirror.registerHelper("hint", "python", pythonHint);
 
   var pythonKeywords = "and del from not while as elif global or with assert else if pass yield"
 + "break except import print class exec in raise continue finally is return def for lambda try";

+ 5 - 0
desktop/core/static/js/codemirror-show-hint.js

@@ -1,3 +1,8 @@
+CodeMirror.registerHelper = function(what, language, hinter) {
+  // avoids JS errors for the unsupported method
+  console.error("Hello Hue dev, we are currently using a version of CodeMirror 3 that does not support .registerHelper. Please use the CodeMirror.languageHint = languageHint syntax instead");
+}
+
 CodeMirror.showHint = function(cm, getHints, options) {
   if (!options) options = {};
   var startCh = cm.getCursor().ch, continued = false;