Skip to content

Commit

Permalink
Merge pull request #1514 from gzzhanghao/autocomplete
Browse files Browse the repository at this point in the history
rfe #1595 make professional code editor suggestion
  • Loading branch information
lem9 committed Feb 21, 2015
2 parents 9f4a2b1 + 2cc8a9c commit f97925d
Show file tree
Hide file tree
Showing 11 changed files with 2,365 additions and 1,121 deletions.
2 changes: 1 addition & 1 deletion db_sql_autocomplete.php
Expand Up @@ -14,7 +14,7 @@
if ($db) {
$tableNames = $GLOBALS['dbi']->getTables($db);
foreach ($tableNames as $tableName) {
$sql_autocomplete[$tableName] = $GLOBALS['dbi']->getColumnNames(
$sql_autocomplete[$tableName] = $GLOBALS['dbi']->getColumns(
$db, $tableName
);
}
Expand Down
6 changes: 1 addition & 5 deletions js/codemirror/LICENSE
@@ -1,4 +1,4 @@
Copyright (C) 2013 by Marijn Haverbeke <marijnh@gmail.com>
Copyright (C) 2014 by Marijn Haverbeke <marijnh@gmail.com> and others

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand All @@ -17,7 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Please note that some subdirectories of the CodeMirror distribution
include their own LICENSE files, and are released under different
licences.
25 changes: 15 additions & 10 deletions js/codemirror/addon/hint/show-hint.js
Expand Up @@ -24,6 +24,18 @@
return cm.showHint(newOpts);
};

var asyncRunID = 0;
function retrieveHints(getter, cm, options, then) {
if (getter.async) {
var id = ++asyncRunID;
getter(cm, function(hints) {
if (asyncRunID == id) then(hints);
}, options);
} else {
then(getter(cm, options));
}
}

CodeMirror.defineExtension("showHint", function(options) {
// We want a single cursor position.
if (this.listSelections().length > 1 || this.somethingSelected()) return;
Expand All @@ -34,10 +46,7 @@
if (!getHints) return;

CodeMirror.signal(this, "startCompletion", this);
if (getHints.async)
getHints(this, function(hints) { completion.showHints(hints); }, completion.options);
else
return completion.showHints(getHints(this, completion.options));
return retrieveHints(getHints, this, completion.options, function(hints) { completion.showHints(hints); });
});

function Completion(cm, options) {
Expand Down Expand Up @@ -102,11 +111,7 @@
function update() {
if (finished) return;
CodeMirror.signal(data, "update");
var getHints = completion.options.hint;
if (getHints.async)
getHints(completion.cm, finishUpdate, completion.options);
else
finishUpdate(getHints(completion.cm, completion.options));
retrieveHints(completion.options.hint, completion.cm, completion.options, finishUpdate);
}
function finishUpdate(data_) {
data = data_;
Expand Down Expand Up @@ -243,7 +248,7 @@
}
}
}
var overlapX = box.left - winW;
var overlapX = box.right - winW;
if (overlapX > 0) {
if (box.right - box.left > winW) {
hints.style.width = (winW - 5) + "px";
Expand Down
162 changes: 108 additions & 54 deletions js/codemirror/addon/hint/sql-hint.js
Expand Up @@ -26,9 +26,26 @@
return CodeMirror.resolveMode(mode).keywords;
}

function getText(item) {
return typeof item == "string" ? item : item.text;
}

function getItem(list, item) {
if (!list.slice) return list[item];
for (var i = list.length - 1; i >= 0; i--) if (getText(list[i]) == item)
return list[i];
}

function shallowClone(object) {
var result = {};
for (var key in object) if (object.hasOwnProperty(key))
result[key] = object[key];
return result;
}

function match(string, word) {
var len = string.length;
var sub = word.substr(0, len);
var sub = getText(word).substr(0, len);
return string.toUpperCase() === sub.toUpperCase();
}

Expand All @@ -44,55 +61,81 @@
}
}

function nameCompletion(result, editor) {
var cur = editor.getCursor();
var token = editor.getTokenAt(cur);
var useBacktick = (token.string.charAt(0) == "`");
var string = token.string.substr(1);
var prevToken = editor.getTokenAt(Pos(cur.line, token.start));
if (token.string.charAt(0) == "." || prevToken.string == "."){
//Suggest colunm names
if (prevToken.string == ".") {
var prevToken = editor.getTokenAt(Pos(cur.line, token.start - 1));
}
var table = prevToken.string;
//Check if backtick is used in table name. If yes, use it for columns too.
var useBacktickTable = false;
if (table.match(/`/g)) {
useBacktickTable = true;
table = table.replace(/`/g, "");
}
//Check if table is available. If not, find table by Alias
if (!tables.hasOwnProperty(table))
table = findTableByAlias(table, editor);
var columns = tables[table];
if (!columns) return;

if (useBacktick) {
addMatches(result, string, columns, function(w) {return "`" + w + "`";});
}
else if(useBacktickTable) {
addMatches(result, string, columns, function(w) {return ".`" + w + "`";});
}
else {
addMatches(result, string, columns, function(w) {return "." + w;});
}
function cleanName(name) {
// Get rid name from backticks(`) and preceding dot(.)
if (name.charAt(0) == ".") {
name = name.substr(1);
}
else {
//Suggest table names or colums in defaultTable
while (token.start && string.charAt(0) == ".") {
token = editor.getTokenAt(Pos(cur.line, token.start - 1));
string = token.string + string;
}
if (useBacktick) {
addMatches(result, string, tables, function(w) {return "`" + w + "`";});
addMatches(result, string, defaultTable, function(w) {return "`" + w + "`";});
}
else {
addMatches(result, string, tables, function(w) {return w;});
addMatches(result, string, defaultTable, function(w) {return w;});
return name.replace(/`/g, "");
}

function insertBackticks(name) {
var nameParts = getText(name).split(".");
for (var i = 0; i < nameParts.length; i++)
nameParts[i] = "`" + nameParts[i] + "`";
var escaped = nameParts.join(".");
if (typeof name == "string") return escaped;
name = shallowClone(name);
name.text = escaped;
return name;
}

function nameCompletion(cur, token, result, editor) {
// Try to complete table, colunm names and return start position of completion
var useBacktick = false;
var nameParts = [];
var start = token.start;
var cont = true;
while (cont) {
cont = (token.string.charAt(0) == ".");
useBacktick = useBacktick || (token.string.charAt(0) == "`");

start = token.start;
nameParts.unshift(cleanName(token.string));

token = editor.getTokenAt(Pos(cur.line, token.start));
if (token.string == ".") {
cont = true;
token = editor.getTokenAt(Pos(cur.line, token.start));
}
}

// Try to complete table names
var string = nameParts.join(".");
addMatches(result, string, tables, function(w) {
return useBacktick ? insertBackticks(w) : w;
});

// Try to complete columns from defaultTable
addMatches(result, string, defaultTable, function(w) {
return useBacktick ? insertBackticks(w) : w;
});

// Try to complete columns
string = nameParts.pop();
var table = nameParts.join(".");

// Check if table is available. If not, find table by Alias
if (!getItem(tables, table))
table = findTableByAlias(table, editor);

var columns = getItem(tables, table);
if (columns && Array.isArray(tables) && columns.columns)
columns = columns.columns;

if (columns) {
addMatches(result, string, columns, function(w) {
if (typeof w == "string") {
w = table + "." + w;
} else {
w = shallowClone(w);
w.text = table + "." + w.text;
}
return useBacktick ? insertBackticks(w) : w;
});
}

return start;
}

function eachWord(lineText, f) {
Expand Down Expand Up @@ -152,12 +195,10 @@
var lineText = query[i];
eachWord(lineText, function(word) {
var wordUpperCase = word.toUpperCase();
if (wordUpperCase === aliasUpperCase && tables.hasOwnProperty(previousWord)) {
table = previousWord;
}
if (wordUpperCase !== CONS.ALIAS_KEYWORD) {
if (wordUpperCase === aliasUpperCase && getItem(tables, previousWord))
table = previousWord;
if (wordUpperCase !== CONS.ALIAS_KEYWORD)
previousWord = word;
}
});
if (table) break;
}
Expand All @@ -167,12 +208,25 @@
CodeMirror.registerHelper("hint", "sql", function(editor, options) {
tables = (options && options.tables) || {};
var defaultTableName = options && options.defaultTable;
defaultTable = (defaultTableName && tables[defaultTableName] || []);
defaultTable = defaultTableName && getItem(tables, defaultTableName);
keywords = keywords || getKeywords(editor);

if (defaultTableName && !defaultTable)
defaultTable = findTableByAlias(defaultTableName, editor);

defaultTable = defaultTable || [];

if (Array.isArray(tables) && defaultTable.columns)
defaultTable = defaultTable.columns;

var cur = editor.getCursor();
var result = [];
var token = editor.getTokenAt(cur), start, end, search;
if (token.end > cur.ch) {
token.end = cur.ch;
token.string = token.string.slice(0, cur.ch - token.start);
}

if (token.string.match(/^[.`\w@]\w*$/)) {
search = token.string;
start = token.start;
Expand All @@ -182,7 +236,7 @@
search = "";
}
if (search.charAt(0) == "." || search.charAt(0) == "`") {
nameCompletion(result, editor);
start = nameCompletion(cur, token, result, editor);
} else {
addMatches(result, search, tables, function(w) {return w;});
addMatches(result, search, defaultTable, function(w) {return w;});
Expand Down
5 changes: 4 additions & 1 deletion js/codemirror/addon/runmode/runmode.js
@@ -1,3 +1,6 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
Expand Down Expand Up @@ -57,7 +60,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) {
for (var i = 0, e = lines.length; i < e; ++i) {
if (i) callback("\n");
var stream = new CodeMirror.StringStream(lines[i]);
if (!stream.string && mode.blankLine) mode.blankLine();
if (!stream.string && mode.blankLine) mode.blankLine(state);
while (!stream.eol()) {
var style = mode.token(stream, state);
callback(stream.current(), style, i, stream.start, state);
Expand Down

0 comments on commit f97925d

Please sign in to comment.