aboutsummaryrefslogtreecommitdiff
path: root/editor-instance.js
diff options
context:
space:
mode:
authorJames Barnett <noreply@jamesbarnett.xyz>2018-02-17 18:03:34 +0000
committerJames Barnett <noreply@jamesbarnett.xyz>2018-02-17 18:03:34 +0000
commit2327e4e536e3be29ffd7af54ebba6ae24265c692 (patch)
tree1441aaa24076633c08fa05da4f17f202e6301af7 /editor-instance.js
parent6e21916395fac6861783c2b930b47242ac0f4c09 (diff)
downloadsql-plus-plus-2327e4e536e3be29ffd7af54ebba6ae24265c692.tar.xz
sql-plus-plus-2327e4e536e3be29ffd7af54ebba6ae24265c692.zip
WIP - Add basic unstyled static tabs. IPC needs work
Diffstat (limited to 'editor-instance.js')
-rw-r--r--editor-instance.js245
1 files changed, 245 insertions, 0 deletions
diff --git a/editor-instance.js b/editor-instance.js
new file mode 100644
index 0000000..3ec123a
--- /dev/null
+++ b/editor-instance.js
@@ -0,0 +1,245 @@
+"use strict";
+
+const { ipcRenderer } = require('electron');
+const $ = window.jQuery = require("jquery");
+require("jquery-ui");
+require("jquery.tabulator");
+const cm = require("codemirror");
+require("codemirror/mode/sql/sql");
+require("codemirror/addon/hint/show-hint.js")
+require("codemirror/addon/hint/sql-hint.js")
+const Split = require("split.js");
+
+const editorContext = cm(document.getElementById("editor"), {
+ value: "select *\nfrom information_schema.tables\n/\nselect now()\n/\nselect *\nfrom foo",
+ mode: "text/x-sql",
+ theme: "dracula",
+ lineNumbers: true,
+ gutters: ["CodeMirror-linenumbers", "statement-pointer"],
+ extraKeys: { "Ctrl-Space": "autocomplete" }
+});
+
+editorContext.on("cursorActivity", (instance) => {
+ let coords = instance.getCursor();
+ $("#cursor-coords").text("Ln " + (parseInt(coords.line) + 1) + ", Col " + (parseInt(coords.ch) + 1));
+});
+
+ipcRenderer.send("queryExecutor.queryTableMetadata");
+ipcRenderer.on("queryExecutor.queryTableMetadataComplete", (event, response) => {
+ console.log(response);
+ cm.commands.autocomplete = function (cmInstance) {
+ cm.showHint(cmInstance, cm.hint.sql, {
+ tables: response.result
+ });
+ }
+});
+
+const statementDelimiter = "/";
+
+let dataTable;
+let execStartTime;
+let execTimerInterval;
+let execElapsedTime;
+let queryMark;
+
+function runQuery() {
+
+ _setExecutionStatusIndicator("RUNNING");
+ _startExecTimer();
+
+ let query = findQuery();
+
+ ipcRenderer.send("queryExecutor.runQuery", query);
+}
+
+/**
+ * If there's selected text, return it. Otherwise find the statement nearest the cursor.
+ * Statements are delimited by lines containing only a "/" character.
+ */
+function findQuery() {
+ let selectedText = editorContext.getSelection();
+
+ if (selectedText !== "") {
+ _clearQueryMarks();
+ return selectedText;
+ }
+ else {
+ let cursorLine = editorContext.getCursor().line;
+
+ let statementStartLine = editorContext.firstLine();
+
+ // lineCount rather than lastLine here, since lineCount is index 1 based.
+ // getRange(from, to) below is 0 based, but the range is exclusive, so if we need to include the last line we need the +1
+ let statementEndLine = editorContext.lineCount();
+
+ // if the current line is a delimiter, thats the end of the statement
+ if (editorContext.getLine(cursorLine) === statementDelimiter) {
+ statementEndLine = cursorLine;
+ }
+ else {
+ // move down the document until a delimiter or the end of the document is reached
+ for (let i = cursorLine + 1; i <= editorContext.lastLine(); i++) {
+ if (editorContext.getLine(i) === statementDelimiter) {
+ statementEndLine = i;
+ break;
+ }
+ }
+ }
+
+ // mode up the document until a previous statements delimiter is found or the start of the document is reached
+ for (let i = cursorLine - 1; i >= editorContext.firstLine(); i--) {
+ if (editorContext.getLine(i) === statementDelimiter) {
+ statementStartLine = i + 1;
+ break;
+ }
+ }
+
+ let query = editorContext.getRange(
+ { line: statementStartLine, ch: 0 },
+ { line: statementEndLine, ch: 0 }
+ );
+
+ console.log(query);
+
+ _clearQueryMarks();
+
+ queryMark = editorContext.markText(
+ { line: statementStartLine, ch: 0 },
+ { line: statementEndLine, ch: 0 },
+ { className: "selected-statement" }
+ );
+
+ editorContext.setGutterMarker(statementStartLine, "statement-pointer", _createGutterMarkerDom());
+
+ return query;
+ }
+}
+
+function _createGutterMarkerDom() {
+ return $("<div> > </div>").get(0);
+}
+
+function _clearQueryMarks() {
+ if (queryMark) {
+ queryMark.clear();
+ }
+ editorContext.clearGutter("statement-pointer");
+}
+
+ipcRenderer.on("queryExecutor.runQueryComplete", (event, response) => {
+ _stopExecTimer();
+ if (response.error === undefined) {
+ handleResult(response.result);
+ }
+ else {
+ handleError(response.error);
+ }
+
+});
+
+function _startExecTimer() {
+ execStartTime = new Date;
+ execElapsedTime = 0;
+ execTimerInterval = setInterval(() => {
+ execElapsedTime = Date.now() - execStartTime;
+ $("#execution-time").text("exec time: " + execElapsedTime + "ms");
+ }, 10);
+}
+
+function _stopExecTimer() {
+ clearInterval(execTimerInterval);
+ execStartTime = null;
+}
+
+function handleError(err) {
+ _stopExecTimer();
+ _destroyDataTable();
+ $("#result-error").removeAttr("style").text("Error (" + err.code + ") - " + err.message);
+ _setExecutionStatusIndicator("ERROR");
+ $("#execution-time").text("failed after " + execElapsedTime + " ms");
+}
+
+function handleResult(results) {
+ _stopExecTimer();
+ _clearErrors();
+ _destroyDataTable();
+
+ dataTable = $("#result-table").tabulator({
+ height: "100%",
+ columns: _mapColumnProperties(results),
+ data: results.rows
+ });
+
+ _setExecutionStatusIndicator("OK");
+ $("#execution-time").text("returned " + results.rowCount + " rows in " + execElapsedTime + " ms");
+}
+
+function _mapColumnProperties(results) {
+ return results.fields.map((column) => {
+ return {
+ field: column.name,
+ title: column.name
+ };
+ });
+}
+
+function _resultTable() {
+ return $("#result-table");
+}
+
+function _setExecutionStatusIndicator(status) {
+ switch (status) {
+ case "RUNNING":
+ $("#execution-status").removeClass().addClass("exec-running").text("Running");
+ break;
+ case "OK":
+ $("#execution-status").removeClass().addClass("exec-ok").text("Ok");
+ break;
+ case "ERROR":
+ $("#execution-status").removeClass().addClass("exec-error").text("Error");
+ break;
+ }
+}
+
+function _destroyDataTable() {
+ if (dataTable) {
+ _resultTable().tabulator("destroy");
+ _resultTable().removeAttr("style").empty();
+ dataTable = undefined;
+ }
+}
+
+function _clearErrors() {
+ $("#result-error").attr("style", "display:none;").empty();
+}
+
+function _onKeyUp(event) {
+ if (event.ctrlKey && event.keyCode == 13) {
+ runQuery();
+ }
+}
+
+$(document).ready(() => {
+
+ // Event handlers
+ $("#run-query").click(runQuery);
+ $(document).keyup(_onKeyUp);
+
+ Split([".editor-row", ".results-row"], {
+ sizes: [50, 50],
+ direction: "vertical",
+ gutterSize: 10,
+ elementStyle: (dimension, size, gutterSize) => {
+ return {
+ "flex-basis": "calc(" + size + "% - " + gutterSize + "px"
+ }
+ },
+ gutterStyle: (dimension, gutterSize) => {
+ return {
+ "flex-basis": gutterSize + "px"
+ }
+ }
+ });
+
+})
+