diff --git a/docs/development/writingzeppelininterpreter.md b/docs/development/writingzeppelininterpreter.md
index d40101b6555..225e41c9fcf 100644
--- a/docs/development/writingzeppelininterpreter.md
+++ b/docs/development/writingzeppelininterpreter.md
@@ -42,7 +42,7 @@ In 'Separate Interpreter(scoped / isolated) for each note' mode which you can se
Creating a new interpreter is quite simple. Just extend [org.apache.zeppelin.interpreter](https://github.com/apache/zeppelin/blob/master/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/Interpreter.java) abstract class and implement some methods.
You can include `org.apache.zeppelin:zeppelin-interpreter:[VERSION]` artifact in your build system. And you should put your jars under your interpreter directory with a specific directory name. Zeppelin server reads interpreter directories recursively and initializes interpreters including your own interpreter.
-There are three locations where you can store your interpreter group, name and other information. Zeppelin server tries to find the location below. Next, Zeppelin tries to find `interpreter-setting.json` in your interpreter jar.
+There are three locations where you can store your interpreter group, name and other information. Zeppelin server tries to find the location below. Next, Zeppelin tries to find `interpreter-setting.json` in your interpreter jar.
```
{ZEPPELIN_INTERPRETER_DIR}/{YOUR_OWN_INTERPRETER_DIR}/interpreter-setting.json
@@ -68,12 +68,15 @@ Here is an example of `interpreter-setting.json` on your own interpreter.
"propertyName": null,
"defaultValue": "property2DefaultValue",
"description": "Property 2 description"
- }, ...
+ },...
+ },
+ "editor": {
+ "language": "your-syntax-highlight-language"
}
},
{
...
- }
+ }
]
```
@@ -96,15 +99,20 @@ some interpreter specific code...
```
## Programming Languages for Interpreter
-If the interpreter uses a specific programming language ( like Scala, Python, SQL ), it is generally recommended to add a syntax highlighting supported for that to the notebook paragraph editor.
+If the interpreter uses a specific programming language (like Scala, Python, SQL), it is generally recommended to add a syntax highlighting supported for that to the notebook paragraph editor.
To check out the list of languages supported, see the `mode-*.js` files under `zeppelin-web/bower_components/ace-builds/src-noconflict` or from [github.com/ajaxorg/ace-builds](https://github.com/ajaxorg/ace-builds/tree/master/src-noconflict).
If you want to add a new set of syntax highlighting,
1. Add the `mode-*.js` file to [zeppelin-web/bower.json](https://github.com/apache/zeppelin/blob/master/zeppelin-web/bower.json) ( when built, [zeppelin-web/src/index.html](https://github.com/apache/zeppelin/blob/master/zeppelin-web/src/index.html) will be changed automatically. ).
-2. Add to the list of `editorMode` in [zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js](https://github.com/apache/zeppelin/blob/master/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js) - it follows the pattern 'ace/mode/x' where x is the name.
-3. Add to the code that checks for `%` prefix and calls `session.setMode(editorMode.x)` in `setParagraphMode` located in [zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js](https://github.com/apache/zeppelin/blob/master/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js).
+2. Add `editor` object to `interpreter-setting.json` file. If you want to set your language to java, add:
+
+ ```
+ "editor": {
+ "language": "java"
+ }
+ ```
## Install your interpreter binary
@@ -216,4 +224,3 @@ We welcome contribution to a new interpreter. Please follow these few steps:
- Add documentation on how to use your interpreter under `docs/interpreter/`. Follow the Markdown style as this [example](https://github.com/apache/zeppelin/blob/master/docs/interpreter/elasticsearch.md). Make sure you list config settings and provide working examples on using your interpreter in code boxes in Markdown. Link to images as appropriate (images should go to `docs/assets/themes/zeppelin/img/docs-img/`). And add a link to your documentation in the navigation menu (`docs/_includes/themes/zeppelin/_navigation.html`).
- Most importantly, ensure licenses of the transitive closure of all dependencies are list in [license file](https://github.com/apache/zeppelin/blob/master/zeppelin-distribution/src/bin_license/LICENSE).
- Commit your changes and open a [Pull Request](https://github.com/apache/zeppelin/pulls) on the project [Mirror on GitHub](https://github.com/apache/zeppelin); check to make sure Travis CI build is passing.
-
diff --git a/flink/src/main/resources/interpreter-setting.json b/flink/src/main/resources/interpreter-setting.json
index 067e7b84e44..e9bd126827f 100644
--- a/flink/src/main/resources/interpreter-setting.json
+++ b/flink/src/main/resources/interpreter-setting.json
@@ -16,6 +16,9 @@
"defaultValue": "6123",
"description": "port of running JobManager."
}
+ },
+ "editor": {
+ "language": "scala"
}
}
]
diff --git a/jdbc/src/main/resources/interpreter-setting.json b/jdbc/src/main/resources/interpreter-setting.json
index 289d4f89ba6..abdb7190d07 100644
--- a/jdbc/src/main/resources/interpreter-setting.json
+++ b/jdbc/src/main/resources/interpreter-setting.json
@@ -154,6 +154,9 @@
"defaultValue": "org.postgresql.Driver",
"description": ""
}
+ },
+ "editor": {
+ "language": "sql"
}
}
]
diff --git a/livy/src/main/resources/interpreter-setting.json b/livy/src/main/resources/interpreter-setting.json
index 2c1a0beceba..70404321304 100644
--- a/livy/src/main/resources/interpreter-setting.json
+++ b/livy/src/main/resources/interpreter-setting.json
@@ -82,6 +82,9 @@
"defaultValue": "",
"description": "Kerberos keytab to authenticate livy"
}
+ },
+ "editor": {
+ "language": "scala"
}
},
{
@@ -100,6 +103,9 @@
"defaultValue": "false",
"description": "Execute multiple SQL concurrently if set true."
}
+ },
+ "editor": {
+ "language": "sql"
}
},
{
@@ -107,6 +113,9 @@
"name": "pyspark",
"className": "org.apache.zeppelin.livy.LivyPySparkInterpreter",
"properties": {
+ },
+ "editor": {
+ "language": "python"
}
},
{
@@ -114,6 +123,9 @@
"name": "sparkr",
"className": "org.apache.zeppelin.livy.LivySparkRInterpreter",
"properties": {
+ },
+ "editor": {
+ "language": "r"
}
}
-]
\ No newline at end of file
+]
diff --git a/python/src/main/resources/interpreter-setting.json b/python/src/main/resources/interpreter-setting.json
index 868b54747c8..f1cd5711daf 100644
--- a/python/src/main/resources/interpreter-setting.json
+++ b/python/src/main/resources/interpreter-setting.json
@@ -16,6 +16,9 @@
"defaultValue": "1000",
"description": "Max number of dataframe rows to display."
}
+ },
+ "editor": {
+ "language": "python"
}
},
{
diff --git a/shell/src/main/resources/interpreter-setting.json b/shell/src/main/resources/interpreter-setting.json
index 5e9a051a2eb..db34607b286 100644
--- a/shell/src/main/resources/interpreter-setting.json
+++ b/shell/src/main/resources/interpreter-setting.json
@@ -10,6 +10,9 @@
"defaultValue": "60000",
"description": "Shell command time out in millisecs. Default = 60000"
}
+ },
+ "editor": {
+ "language": "sh"
}
}
-]
\ No newline at end of file
+]
diff --git a/spark/src/main/resources/interpreter-setting.json b/spark/src/main/resources/interpreter-setting.json
index 2343a0f9745..2d80bba9ceb 100644
--- a/spark/src/main/resources/interpreter-setting.json
+++ b/spark/src/main/resources/interpreter-setting.json
@@ -54,6 +54,9 @@
"defaultValue": "local[*]",
"description": "Spark master uri. ex) spark://masterhost:7077"
}
+ },
+ "editor": {
+ "language": "scala"
}
},
{
@@ -85,6 +88,9 @@
"defaultValue": "true",
"description": "Import implicits, UDF collection, and sql if set true. true by default."
}
+ },
+ "editor": {
+ "language": "sql"
}
},
{
@@ -104,6 +110,9 @@
"defaultValue": "spark-packages,http://dl.bintray.com/spark-packages/maven,false;",
"description": "A list of 'id,remote-repository-URL,is-snapshot;' for each remote repository."
}
+ },
+ "editor": {
+ "language": "scala"
}
},
{
@@ -117,6 +126,9 @@
"defaultValue": "python",
"description": "Python command to run pyspark with"
}
+ },
+ "editor": {
+ "language": "python"
}
}
]
diff --git a/spark/src/main/sparkr-resources/interpreter-setting.json b/spark/src/main/sparkr-resources/interpreter-setting.json
index 4902baf9f76..61f984a5ea4 100644
--- a/spark/src/main/sparkr-resources/interpreter-setting.json
+++ b/spark/src/main/sparkr-resources/interpreter-setting.json
@@ -54,6 +54,9 @@
"defaultValue": "local[*]",
"description": "Spark master uri. ex) spark://masterhost:7077"
}
+ },
+ "editor": {
+ "language": "scala"
}
},
{
@@ -85,6 +88,9 @@
"defaultValue": "true",
"description": "Import implicits, UDF collection, and sql if set true. true by default."
}
+ },
+ "editor": {
+ "language": "sql"
}
},
{
@@ -104,6 +110,9 @@
"defaultValue": "spark-packages,http://dl.bintray.com/spark-packages/maven,false;",
"description": "A list of 'id,remote-repository-URL,is-snapshot;' for each remote repository."
}
+ },
+ "editor": {
+ "language": "scala"
}
},
{
@@ -117,6 +126,9 @@
"defaultValue": "python",
"description": "Python command to run pyspark with"
}
+ },
+ "editor": {
+ "language": "python"
}
},
{
@@ -148,6 +160,9 @@
"defaultValue": "out.format = 'html', comment = NA, echo = FALSE, results = 'asis', message = F, warning = F",
"description": ""
}
+ },
+ "editor": {
+ "language": "r"
}
}
]
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/Interpreter.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/Interpreter.java
index 07f9cbabcad..cdd2f6338b3 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/Interpreter.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/Interpreter.java
@@ -251,6 +251,7 @@ public static class RegisteredInterpreter {
private String className;
private boolean defaultInterpreter;
private Map properties;
+ private Map editor;
private String path;
public RegisteredInterpreter(String name, String group, String className,
@@ -266,6 +267,7 @@ public RegisteredInterpreter(String name, String group, String className,
this.className = className;
this.defaultInterpreter = defaultInterpreter;
this.properties = properties;
+ this.editor = new HashMap<>();
}
public String getName() {
@@ -292,6 +294,10 @@ public Map getProperties() {
return properties;
}
+ public Map getEditor() {
+ return editor;
+ }
+
public void setPath(String path) {
this.path = path;
}
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
index 853c0d5c524..d0fd0f5853e 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
@@ -226,6 +226,9 @@ public void onMessage(NotebookSocket conn, String msg) {
case LIST_UPDATE_NOTEBOOK_JOBS:
unicastUpdateNotebookJobInfo(conn, messagereceived);
break;
+ case EDITOR_SETTING:
+ getEditorSetting(conn, notebook, messagereceived);
+ break;
default:
break;
}
@@ -1259,7 +1262,7 @@ public void afterStatusChange(Job job, Status before, Status after) {
}
/**
- * This callback is for praragraph that runs on RemoteInterpreterProcess
+ * This callback is for paragraph that runs on RemoteInterpreterProcess
* @param paragraph
* @param out
* @param output
@@ -1367,11 +1370,24 @@ public void onRemove(String interpreterGroupId, String name, String noteId, Stri
if (id.equals(interpreterGroupId)) {
broadcast(
note.id(),
- new Message(OP.ANGULAR_OBJECT_REMOVE).put("name", name).put(
- "noteId", noteId).put("paragraphId", paragraphId));
+ new Message(OP.ANGULAR_OBJECT_REMOVE)
+ .put("name", name)
+ .put("noteId", noteId)
+ .put("paragraphId", paragraphId));
}
}
}
}
+
+ private void getEditorSetting(NotebookSocket conn, Notebook notebook, Message fromMessage)
+ throws IOException {
+ String replName = (String) fromMessage.get("magic");
+ String noteId = getOpenNoteId(conn);
+ Note note = notebook.getNote(noteId);
+ Message resp = new Message(OP.EDITOR_SETTING);
+ resp.put("editor", note.getEditorSetting(replName));
+ conn.send(serializeMessage(resp));
+ return;
+ }
}
diff --git a/zeppelin-web/bower.json b/zeppelin-web/bower.json
index 5d849b3490d..f0f9443817b 100644
--- a/zeppelin-web/bower.json
+++ b/zeppelin-web/bower.json
@@ -24,7 +24,7 @@
"angular-elastic": "~2.4.2",
"angular-elastic-input": "~2.2.0",
"angular-xeditable": "0.1.12",
- "highlightjs": "^9.2.0",
+ "highlightjs": "^9.4.0",
"lodash": "~3.9.3",
"angular-filter": "~0.5.4",
"ngtoast": "~2.0.0",
@@ -59,7 +59,7 @@
"highlight.pack.js",
"styles/github.css"
],
- "version": "8.4.0",
+ "version": "9.4.0",
"name": "highlightjs"
}
}
diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
index fcf609eac2c..d2939d37ebd 100644
--- a/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
+++ b/zeppelin-web/src/app/notebook/paragraph/paragraph.controller.js
@@ -16,7 +16,7 @@
angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $rootScope, $route, $window,
$routeParams, $location, $timeout, $compile,
- $http, websocketMsgSrv, baseUrlSrv, ngToast,
+ $http, $q, websocketMsgSrv, baseUrlSrv, ngToast,
SaveAsService) {
var ANGULAR_FUNCTION_OBJECT_NAME_PREFIX = '_Z_ANGULAR_FUNC_';
$scope.parentNote = null;
@@ -80,12 +80,8 @@ angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
var angularObjectRegistry = {};
var editorModes = {
- 'ace/mode/python': /^%(\w*\.)?(pyspark|python)\s*$/,
- 'ace/mode/scala': /^%(\w*\.)?spark\s*$/,
- 'ace/mode/r': /^%(\w*\.)?(r|sparkr|knitr)\s*$/,
'ace/mode/sql': /^%(\w*\.)?\wql/,
- 'ace/mode/markdown': /^%md/,
- 'ace/mode/sh': /^%sh/
+ 'ace/mode/markdown': /^%md/
};
// Controller init
@@ -526,7 +522,7 @@ angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
$scope.startSaveTimer();
$timeout(function() {
- $scope.setParagraphMode($scope.editor.getSession(), $scope.dirtyText, $scope.editor.getCursorPosition());
+ setParagraphMode($scope.editor.getSession(), $scope.dirtyText, $scope.editor.getCursorPosition());
});
};
@@ -563,37 +559,11 @@ angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
// not applying emacs key binding while the binding override Ctrl-v. default behavior of paste text on windows.
}
- $scope.setParagraphMode = function(session, paragraphText, pos) {
- // Evaluate the mode only if the first 30 characters of the paragraph have been modified or the the position is undefined.
- if ((typeof pos === 'undefined') || (pos.row === 0 && pos.column < 30)) {
- // If paragraph loading, use config value if exists
- if ((typeof pos === 'undefined') && $scope.paragraph.config.editorMode) {
- session.setMode($scope.paragraph.config.editorMode);
- } else {
- // Defaults to spark mode
- var newMode = 'ace/mode/scala';
- // Test first against current mode
- var oldMode = session.getMode().$id;
- if (!editorModes[oldMode] || !editorModes[oldMode].test(paragraphText)) {
- for (var key in editorModes) {
- if (key !== oldMode) {
- if (editorModes[key].test(paragraphText)) {
- $scope.paragraph.config.editorMode = key;
- session.setMode(key);
- return true;
- }
- }
- }
- $scope.paragraph.config.editorMode = newMode;
- session.setMode(newMode);
- }
- }
- }
- };
-
var remoteCompleter = {
getCompletions: function(editor, session, pos, prefix, callback) {
- if (!$scope.editor.isFocused()) { return;}
+ if (!$scope.editor.isFocused()) {
+ return;
+ }
pos = session.getTextRange(new Range(0, 0, pos.row, pos.column)).length;
var buf = session.getValue();
@@ -647,7 +617,7 @@ angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
autoAdjustEditorHeight(_editor.container.id);
});
- $scope.setParagraphMode($scope.editor.getSession(), $scope.editor.getSession().getValue());
+ setParagraphMode($scope.editor.getSession(), $scope.editor.getSession().getValue());
// autocomplete on '.'
/*
@@ -710,6 +680,70 @@ angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
}
};
+ var getEditorSetting = function(interpreterName) {
+ var deferred = $q.defer();
+ websocketMsgSrv.getEditorSetting(interpreterName);
+ $timeout(
+ $scope.$on('editorSetting', function(event, data) {
+ deferred.resolve(data);
+ }
+ ), 1000);
+ return deferred.promise;
+ };
+
+ var setParagraphMode = function(session, paragraphText, pos) {
+ // Evaluate the mode only if the the position is undefined
+ // or the first 30 characters of the paragraph have been modified
+ // or cursor position is at beginning of second line.(in case user hit enter after typing %magic)
+ if ((typeof pos === 'undefined') || (pos.row === 0 && pos.column < 30) || (pos.row === 1 && pos.column === 0)) {
+ // If paragraph loading, use config value if exists
+ if ((typeof pos === 'undefined') && $scope.paragraph.config.editorMode) {
+ session.setMode($scope.paragraph.config.editorMode);
+ } else {
+ var magic;
+ // set editor mode to default interpreter syntax if paragraph text doesn't start with '%'
+ if (!paragraphText.startsWith('%')) {
+ magic = $scope.$parent.interpreterBindings[0].group;
+ } else {
+ var replNameRegexp = /%(.+?)\s/g;
+ var match = replNameRegexp.exec(paragraphText);
+ if (match) {
+ magic = match[1];
+ }
+ }
+ if (magic) {
+ var promise = getEditorSetting(magic);
+ promise.then(function(editorSetting) {
+ if (!_.isEmpty(editorSetting.editor)) {
+ var mode = 'ace/mode/' + editorSetting.editor.language;
+ $scope.paragraph.config.editorMode = mode;
+ session.setMode(mode);
+ }
+ // TODO(mina): remove else condition once register machanism of all interpreter changed
+ else {
+ var newMode = 'ace/mode/scala';
+ // Test first against current mode
+ var oldMode = session.getMode().$id;
+ if (!editorModes[oldMode] || !editorModes[oldMode].test(paragraphText)) {
+ for (var key in editorModes) {
+ if (key !== oldMode) {
+ if (editorModes[key].test(paragraphText)) {
+ $scope.paragraph.config.editorMode = key;
+ session.setMode(key);
+ return true;
+ }
+ }
+ }
+ $scope.paragraph.config.editorMode = newMode;
+ session.setMode(newMode);
+ }
+ }
+ });
+ }
+ }
+ }
+ };
+
var autoAdjustEditorHeight = function(id) {
var editor = $scope.editor;
var height = editor.getSession().getScreenLength() * editor.renderer.lineHeight +
@@ -1102,11 +1136,11 @@ angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
}
var chartEl = d3.select('#p' + $scope.paragraph.id + '_' + type + ' svg')
- .attr('height', $scope.paragraph.config.graph.height)
- .datum(d3g)
- .transition()
- .duration(animationDuration)
- .call($scope.chart[type]);
+ .attr('height', $scope.paragraph.config.graph.height)
+ .datum(d3g)
+ .transition()
+ .duration(animationDuration)
+ .call($scope.chart[type]);
d3.select('#p' + $scope.paragraph.id + '_' + type + ' svg').style.height = height + 'px';
nv.utils.windowResize($scope.chart[type].update);
};
@@ -1946,7 +1980,6 @@ angular.module('zeppelinWebApp').controller('ParagraphCtrl', function($scope, $r
var noteId = $route.current.pathParams.noteId;
$http.get(baseUrlSrv.getRestApiBase() + '/helium/suggest/' + noteId + '/' + $scope.paragraph.id)
.success(function(data, status, headers, config) {
- console.log('Suggested apps %o', data);
$scope.suggestion = data.body;
})
.error(function(err, status, headers, config) {
diff --git a/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js b/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js
index 2fb5003ba15..d26b7266ad4 100644
--- a/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js
+++ b/zeppelin-web/src/components/websocketEvents/websocketEvents.factory.js
@@ -76,8 +76,8 @@ angular.module('zeppelinWebApp').factory('websocketEvents',
action: function(dialog) {
dialog.close();
angular.element('#loginModal').modal({
- show: 'true'
- });
+ show: 'true'
+ });
}
}, {
label: 'Cancel',
@@ -97,6 +97,8 @@ angular.module('zeppelinWebApp').factory('websocketEvents',
$rootScope.$broadcast('updateProgress', data);
} else if (op === 'COMPLETION_LIST') {
$rootScope.$broadcast('completionList', data);
+ } else if (op === 'EDITOR_SETTING') {
+ $rootScope.$broadcast('editorSetting', data);
} else if (op === 'ANGULAR_OBJECT_UPDATE') {
$rootScope.$broadcast('angularObjectUpdate', data);
} else if (op === 'ANGULAR_OBJECT_REMOVE') {
diff --git a/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
index 698b8ff8100..a2f9f072d14 100644
--- a/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
+++ b/zeppelin-web/src/components/websocketEvents/websocketMsg.service.js
@@ -161,6 +161,15 @@ angular.module('zeppelinWebApp').service('websocketMsgSrv', function($rootScope,
});
},
+ getEditorSetting: function(replName) {
+ websocketEvents.sendNewEvent({
+ op: 'EDITOR_SETTING',
+ data: {
+ magic: replName
+ }
+ });
+ },
+
isConnected: function() {
return websocketEvents.isConnected();
},
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
index 9106cf5f17c..ca66efd43f1 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java
@@ -650,6 +650,21 @@ public String getLastInterpreterName() {
return getInterpreterName(getLastReplName());
}
+ public Interpreter getRepl(String name) {
+ return factory.getInterpreter(id(), name);
+ }
+
+ public Map getEditorSetting(String replName) {
+ Interpreter intp = getRepl(replName);
+ Map editor = new HashMap<>();
+ try {
+ editor = intp.findRegisteredInterpreterByClassName(intp.getClassName()).getEditor();
+ } catch (NullPointerException e) {
+ editor.put("language", "text");
+ }
+ return editor;
+ }
+
@Override
public void beforeStatusChange(Job job, Status before, Status after) {
if (jobListenerFactory != null) {
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java
index 73174061cad..063b56ba947 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java
@@ -202,7 +202,7 @@ public static String getScriptBody(String text) {
}
public Interpreter getRepl(String name) {
- return factory.getInterpreter(note.getId(), name);
+ return note.getRepl(name);
}
public Interpreter getCurrentRepl() {
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
index 08b32359226..9463841f3fe 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/socket/Message.java
@@ -21,43 +21,43 @@
import java.util.Map;
/**
- * Zeppelin websocker massage template class.
+ * Zeppelin websocket massage template class.
*/
public class Message {
/**
* Representation of event type.
*/
public static enum OP {
- GET_HOME_NOTE, // [c-s] load note for home screen
+ GET_HOME_NOTE, // [c-s] load note for home screen
- GET_NOTE, // [c-s] client load note
- // @param id note id
+ GET_NOTE, // [c-s] client load note
+ // @param id note id
- NOTE, // [s-c] note info
- // @param note serlialized Note object
+ NOTE, // [s-c] note info
+ // @param note serlialized Note object
- PARAGRAPH, // [s-c] paragraph info
- // @param paragraph serialized paragraph object
+ PARAGRAPH, // [s-c] paragraph info
+ // @param paragraph serialized paragraph object
- PROGRESS, // [s-c] progress update
- // @param id paragraph id
- // @param progress percentage progress
-
- NEW_NOTE, // [c-s] create new notebook
- DEL_NOTE, // [c-s] delete notebook
- // @param id note id
- CLONE_NOTE, // [c-s] clone new notebook
- // @param id id of note to clone
- // @param name name fpor the cloned note
- IMPORT_NOTE, // [c-s] import notebook
- // @param object notebook
+ PROGRESS, // [s-c] progress update
+ // @param id paragraph id
+ // @param progress percentage progress
+
+ NEW_NOTE, // [c-s] create new notebook
+ DEL_NOTE, // [c-s] delete notebook
+ // @param id note id
+ CLONE_NOTE, // [c-s] clone new notebook
+ // @param id id of note to clone
+ // @param name name fpor the cloned note
+ IMPORT_NOTE, // [c-s] import notebook
+ // @param object notebook
NOTE_UPDATE,
- RUN_PARAGRAPH, // [c-s] run paragraph
- // @param id paragraph id
- // @param paragraph paragraph content.ie. script
- // @param config paragraph config
- // @param params paragraph params
+ RUN_PARAGRAPH, // [c-s] run paragraph
+ // @param id paragraph id
+ // @param paragraph paragraph content.ie. script
+ // @param config paragraph config
+ // @param params paragraph params
COMMIT_PARAGRAPH, // [c-s] commit paragraph
// @param id paragraph id
@@ -69,60 +69,64 @@ public static enum OP {
CANCEL_PARAGRAPH, // [c-s] cancel paragraph run
// @param id paragraph id
- MOVE_PARAGRAPH, // [c-s] move paragraph order
- // @param id paragraph id
- // @param index index the paragraph want to go
+ MOVE_PARAGRAPH, // [c-s] move paragraph order
+ // @param id paragraph id
+ // @param index index the paragraph want to go
INSERT_PARAGRAPH, // [c-s] create new paragraph below current paragraph
// @param target index
- COMPLETION, // [c-s] ask completion candidates
- // @param id
- // @param buf current code
- // @param cursor cursor position in code
+ EDITOR_SETTING, // [c-s] ask paragraph editor setting
+ // @param magic magic keyword written in paragraph
+ // ex) spark.spark or spark
+
+ COMPLETION, // [c-s] ask completion candidates
+ // @param id
+ // @param buf current code
+ // @param cursor cursor position in code
- COMPLETION_LIST, // [s-c] send back completion candidates list
- // @param id
- // @param completions list of string
+ COMPLETION_LIST, // [s-c] send back completion candidates list
+ // @param id
+ // @param completions list of string
- LIST_NOTES, // [c-s] ask list of note
- RELOAD_NOTES_FROM_REPO, // [c-s] reload notes from repo
+ LIST_NOTES, // [c-s] ask list of note
+ RELOAD_NOTES_FROM_REPO, // [c-s] reload notes from repo
- NOTES_INFO, // [s-c] list of note infos
- // @param notes serialized List object
+ NOTES_INFO, // [s-c] list of note infos
+ // @param notes serialized List object
PARAGRAPH_REMOVE,
PARAGRAPH_CLEAR_OUTPUT,
- PARAGRAPH_APPEND_OUTPUT, // [s-c] append output
- PARAGRAPH_UPDATE_OUTPUT, // [s-c] update (replace) output
+ PARAGRAPH_APPEND_OUTPUT, // [s-c] append output
+ PARAGRAPH_UPDATE_OUTPUT, // [s-c] update (replace) output
PING,
AUTH_INFO,
- ANGULAR_OBJECT_UPDATE, // [s-c] add/update angular object
- ANGULAR_OBJECT_REMOVE, // [s-c] add angular object del
+ ANGULAR_OBJECT_UPDATE, // [s-c] add/update angular object
+ ANGULAR_OBJECT_REMOVE, // [s-c] add angular object del
- ANGULAR_OBJECT_UPDATED, // [c-s] angular object value updated,
+ ANGULAR_OBJECT_UPDATED, // [c-s] angular object value updated,
- ANGULAR_OBJECT_CLIENT_BIND, // [c-s] angular object updated from AngularJS z object
+ ANGULAR_OBJECT_CLIENT_BIND, // [c-s] angular object updated from AngularJS z object
- ANGULAR_OBJECT_CLIENT_UNBIND, // [c-s] angular object unbind from AngularJS z object
+ ANGULAR_OBJECT_CLIENT_UNBIND, // [c-s] angular object unbind from AngularJS z object
- LIST_CONFIGURATIONS, // [c-s] ask all key/value pairs of configurations
- CONFIGURATIONS_INFO, // [s-c] all key/value pairs of configurations
- // @param settings serialized Map object
+ LIST_CONFIGURATIONS, // [c-s] ask all key/value pairs of configurations
+ CONFIGURATIONS_INFO, // [s-c] all key/value pairs of configurations
+ // @param settings serialized Map object
- CHECKPOINT_NOTEBOOK, // [c-s] checkpoint notebook to storage repository
- // @param noteId
- // @param checkpointName
+ CHECKPOINT_NOTEBOOK, // [c-s] checkpoint notebook to storage repository
+ // @param noteId
+ // @param checkpointName
- APP_APPEND_OUTPUT, // [s-c] append output
- APP_UPDATE_OUTPUT, // [s-c] update (replace) output
- APP_LOAD, // [s-c] on app load
- APP_STATUS_CHANGE, // [s-c] on app status change
+ APP_APPEND_OUTPUT, // [s-c] append output
+ APP_UPDATE_OUTPUT, // [s-c] update (replace) output
+ APP_LOAD, // [s-c] on app load
+ APP_STATUS_CHANGE, // [s-c] on app status change
- LIST_NOTEBOOK_JOBS, // [c-s] get notebook job management infomations
- LIST_UPDATE_NOTEBOOK_JOBS // [c-s] get job management informations for until unixtime
- // @param unixTime
+ LIST_NOTEBOOK_JOBS, // [c-s] get notebook job management information
+ LIST_UPDATE_NOTEBOOK_JOBS // [c-s] get job management information for until unixtime
+ // @param unixTime
}
public OP op;
diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java
index cff66adc78d..2c2f4a56c6e 100644
--- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java
+++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NoteTest.java
@@ -17,8 +17,6 @@
package org.apache.zeppelin.notebook;
-import com.google.common.base.Optional;
-
import org.apache.commons.lang.StringUtils;
import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterFactory;
@@ -106,7 +104,7 @@ public void runJdbcTest() {
@Test
public void putDefaultReplNameIfInterpreterSettingAbsent() {
when(interpreterFactory.getDefaultInterpreterSetting(anyString()))
- .thenReturn(null);
+ .thenReturn(null);
Note note = new Note(repo, interpreterFactory, jobListenerFactory, index, credentials, noteEventListener);
note.putDefaultReplName();
diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java
index bfa97e05de3..d2f73cb1c29 100644
--- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java
+++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java
@@ -73,10 +73,15 @@ public void setUp() throws Exception {
new File(tmpDir, "conf").mkdirs();
notebookDir = new File(tmpDir + "/notebook");
notebookDir.mkdirs();
+ FileUtils.copyDirectory(new File("src/test/resources/interpreter"), new File(tmpDir, "interpreter"));
+ System.setProperty(ConfVars.ZEPPELIN_CONF_DIR.getVarName(), tmpDir.toString() + "/conf");
System.setProperty(ConfVars.ZEPPELIN_HOME.getVarName(), tmpDir.getAbsolutePath());
System.setProperty(ConfVars.ZEPPELIN_NOTEBOOK_DIR.getVarName(), notebookDir.getAbsolutePath());
- System.setProperty(ConfVars.ZEPPELIN_INTERPRETERS.getVarName(), "org.apache.zeppelin.interpreter.mock.MockInterpreter1,org.apache.zeppelin.interpreter.mock.MockInterpreter2");
+ System.setProperty(ConfVars.ZEPPELIN_INTERPRETERS.getVarName(),
+ "org.apache.zeppelin.interpreter.mock.MockInterpreter1," +
+ "org.apache.zeppelin.interpreter.mock.MockInterpreter2," +
+ "org.apache.zeppelin.interpreter.mock.MockInterpreter11");
conf = ZeppelinConfiguration.create();
@@ -94,8 +99,7 @@ public void setUp() throws Exception {
credentials = new Credentials(conf.credentialsPersist(), conf.getCredentialsPath());
notebook = new Notebook(conf, notebookRepo, schedulerFactory, factory, this, search,
- notebookAuthorization, credentials);
-
+ notebookAuthorization, credentials);
}
@After
@@ -825,6 +829,30 @@ else if(file.isDirectory()){
}
}
+ @Test
+ public void getEditorSetting() throws IOException, RepositoryException, SchedulerException {
+ List intpIds = new ArrayList<>();
+ for(InterpreterSetting intpSetting: factory.get()) {
+ if (intpSetting.getName().startsWith("mock1")) {
+ intpIds.add(intpSetting.id());
+ }
+ }
+ Note note = notebook.createNote(intpIds, null);
+
+ // get editor setting from interpreter-setting.json
+ Map editor = note.getEditorSetting("mock11");
+ assertEquals("java", editor.get("language"));
+
+ // when interpreter is not loaded via interpreter-setting.json
+ // or editor setting doesn't exit
+ editor = note.getEditorSetting("mock1");
+ assertEquals(null, editor.get("language"));
+
+ // when interpreter is not bound to note
+ editor = note.getEditorSetting("mock2");
+ assertEquals("text", editor.get("language"));
+ }
+
@Override
public ParagraphJobListener getParagraphJobListener(Note note) {
return new ParagraphJobListener(){
diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTest.java
index 1f8519cb399..48814bb1da7 100644
--- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTest.java
+++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/ParagraphTest.java
@@ -85,7 +85,7 @@ public void effectiveTextTest() {
assertEquals("Get right replName", "jdbc", p.getRequiredReplName());
assertEquals("Get right scriptBody", "(h2) show databases", p.getScriptBody());
- when(interpreterFactory.getInterpreter(anyString(), eq("jdbc"))).thenReturn(interpreter);
+ when(note.getRepl(eq("jdbc"))).thenReturn(interpreter);
when(interpreter.getFormType()).thenReturn(Interpreter.FormType.NATIVE);
when(note.getId()).thenReturn("noteId");
diff --git a/zeppelin-zengine/src/test/resources/interpreter/mock/interpreter-setting.json b/zeppelin-zengine/src/test/resources/interpreter/mock/interpreter-setting.json
new file mode 100644
index 00000000000..65568ef8a5c
--- /dev/null
+++ b/zeppelin-zengine/src/test/resources/interpreter/mock/interpreter-setting.json
@@ -0,0 +1,12 @@
+[
+ {
+ "group": "mock11",
+ "name": "mock11",
+ "className": "org.apache.zeppelin.interpreter.mock.MockInterpreter11",
+ "properties": {
+ },
+ "editor": {
+ "language": "java"
+ }
+ }
+]