Created
September 10, 2015 19:08
-
-
Save addamh/4112619016ab5e88ed96 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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"), require("./xml-hint")); | |
else if (typeof define == "function" && define.amd) // AMD | |
define(["../../lib/codemirror", "./xml-hint"], mod); | |
else // Plain browser env | |
mod(CodeMirror); | |
})(function(CodeMirror) { | |
"use strict"; | |
var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" "); | |
var targets = ["_blank", "_self", "_top", "_parent"]; | |
var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"]; | |
var methods = ["get", "post", "put", "delete"]; | |
var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]; | |
var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech", | |
"3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait", | |
"orientation:landscape", "device-height: [X]", "device-width: [X]"]; | |
var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags | |
var data = { | |
a: { | |
attrs: { | |
href: null, ping: null, type: null, | |
media: media, | |
target: targets, | |
hreflang: langs | |
} | |
}, | |
abbr: s, | |
acronym: s, | |
address: s, | |
applet: s, | |
area: { | |
attrs: { | |
alt: null, coords: null, href: null, target: null, ping: null, | |
media: media, hreflang: langs, type: null, | |
shape: ["default", "rect", "circle", "poly"] | |
} | |
}, | |
article: s, | |
aside: s, | |
audio: { | |
attrs: { | |
src: null, mediagroup: null, | |
crossorigin: ["anonymous", "use-credentials"], | |
preload: ["none", "metadata", "auto"], | |
autoplay: ["", "autoplay"], | |
loop: ["", "loop"], | |
controls: ["", "controls"] | |
} | |
}, | |
b: s, | |
base: { attrs: { href: null, target: targets } }, | |
basefont: s, | |
bdi: s, | |
bdo: s, | |
big: s, | |
blockquote: { attrs: { cite: null } }, | |
body: s, | |
br: s, | |
button: { | |
attrs: { | |
form: null, formaction: null, name: null, value: null, | |
autofocus: ["", "autofocus"], | |
disabled: ["", "autofocus"], | |
formenctype: encs, | |
formmethod: methods, | |
formnovalidate: ["", "novalidate"], | |
formtarget: targets, | |
type: ["submit", "reset", "button"] | |
} | |
}, | |
canvas: { attrs: { width: null, height: null } }, | |
caption: s, | |
center: s, | |
cite: s, | |
code: s, | |
col: { attrs: { span: null } }, | |
colgroup: { attrs: { span: null } }, | |
command: { | |
attrs: { | |
type: ["command", "checkbox", "radio"], | |
label: null, icon: null, radiogroup: null, command: null, title: null, | |
disabled: ["", "disabled"], | |
checked: ["", "checked"] | |
} | |
}, | |
data: { attrs: { value: null } }, | |
datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } }, | |
datalist: { attrs: { data: null } }, | |
dd: s, | |
del: { attrs: { cite: null, datetime: null } }, | |
details: { attrs: { open: ["", "open"] } }, | |
dfn: s, | |
dir: s, | |
div: s, | |
dl: s, | |
dt: s, | |
em: s, | |
embed: { attrs: { src: null, type: null, width: null, height: null } }, | |
eventsource: { attrs: { src: null } }, | |
fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } }, | |
figcaption: s, | |
figure: s, | |
font: s, | |
footer: s, | |
form: { | |
attrs: { | |
action: null, name: null, | |
"accept-charset": charsets, | |
autocomplete: ["on", "off"], | |
enctype: encs, | |
method: methods, | |
novalidate: ["", "novalidate"], | |
target: targets | |
} | |
}, | |
frame: s, | |
frameset: s, | |
h1: s, h2: s, h3: s, h4: s, h5: s, h6: s, | |
head: { | |
attrs: {}, | |
children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"] | |
}, | |
header: s, | |
hgroup: s, | |
hr: s, | |
html: { | |
attrs: { manifest: null }, | |
children: ["head", "body"] | |
}, | |
i: s, | |
iframe: { | |
attrs: { | |
src: null, srcdoc: null, name: null, width: null, height: null, | |
sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"], | |
seamless: ["", "seamless"] | |
} | |
}, | |
img: { | |
attrs: { | |
alt: null, src: null, ismap: null, usemap: null, width: null, height: null, | |
crossorigin: ["anonymous", "use-credentials"] | |
} | |
}, | |
input: { | |
attrs: { | |
alt: null, dirname: null, form: null, formaction: null, | |
height: null, list: null, max: null, maxlength: null, min: null, | |
name: null, pattern: null, placeholder: null, size: null, src: null, | |
step: null, value: null, width: null, | |
accept: ["audio/*", "video/*", "image/*"], | |
autocomplete: ["on", "off"], | |
autofocus: ["", "autofocus"], | |
checked: ["", "checked"], | |
disabled: ["", "disabled"], | |
formenctype: encs, | |
formmethod: methods, | |
formnovalidate: ["", "novalidate"], | |
formtarget: targets, | |
multiple: ["", "multiple"], | |
readonly: ["", "readonly"], | |
required: ["", "required"], | |
type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month", | |
"week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio", | |
"file", "submit", "image", "reset", "button"] | |
} | |
}, | |
ins: { attrs: { cite: null, datetime: null } }, | |
kbd: s, | |
keygen: { | |
attrs: { | |
challenge: null, form: null, name: null, | |
autofocus: ["", "autofocus"], | |
disabled: ["", "disabled"], | |
keytype: ["RSA"] | |
} | |
}, | |
label: { attrs: { "for": null, form: null } }, | |
legend: s, | |
li: { attrs: { value: null } }, | |
link: { | |
attrs: { | |
href: null, type: null, | |
hreflang: langs, | |
media: media, | |
sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"] | |
} | |
}, | |
map: { attrs: { name: null } }, | |
mark: s, | |
menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } }, | |
meta: { | |
attrs: { | |
content: null, | |
charset: charsets, | |
name: ["viewport", "application-name", "author", "description", "generator", "keywords"], | |
"http-equiv": ["content-language", "content-type", "default-style", "refresh"] | |
} | |
}, | |
meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } }, | |
nav: s, | |
noframes: s, | |
noscript: s, | |
object: { | |
attrs: { | |
data: null, type: null, name: null, usemap: null, form: null, width: null, height: null, | |
typemustmatch: ["", "typemustmatch"] | |
} | |
}, | |
ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } }, | |
optgroup: { attrs: { disabled: ["", "disabled"], label: null } }, | |
option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } }, | |
output: { attrs: { "for": null, form: null, name: null } }, | |
p: s, | |
param: { attrs: { name: null, value: null } }, | |
pre: s, | |
progress: { attrs: { value: null, max: null } }, | |
q: { attrs: { cite: null } }, | |
rp: s, | |
rt: s, | |
ruby: s, | |
s: s, | |
samp: s, | |
script: { | |
attrs: { | |
type: ["text/javascript"], | |
src: null, | |
async: ["", "async"], | |
defer: ["", "defer"], | |
charset: charsets | |
} | |
}, | |
section: s, | |
select: { | |
attrs: { | |
form: null, name: null, size: null, | |
autofocus: ["", "autofocus"], | |
disabled: ["", "disabled"], | |
multiple: ["", "multiple"] | |
} | |
}, | |
small: s, | |
source: { attrs: { src: null, type: null, media: null } }, | |
span: s, | |
strike: s, | |
strong: s, | |
style: { | |
attrs: { | |
type: ["text/css"], | |
media: media, | |
scoped: null | |
} | |
}, | |
sub: s, | |
summary: s, | |
sup: s, | |
table: s, | |
tbody: s, | |
td: { attrs: { colspan: null, rowspan: null, headers: null } }, | |
textarea: { | |
attrs: { | |
dirname: null, form: null, maxlength: null, name: null, placeholder: null, | |
rows: null, cols: null, | |
autofocus: ["", "autofocus"], | |
disabled: ["", "disabled"], | |
readonly: ["", "readonly"], | |
required: ["", "required"], | |
wrap: ["soft", "hard"] | |
} | |
}, | |
tfoot: s, | |
th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } }, | |
thead: s, | |
time: { attrs: { datetime: null } }, | |
title: s, | |
tr: s, | |
track: { | |
attrs: { | |
src: null, label: null, "default": null, | |
kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"], | |
srclang: langs | |
} | |
}, | |
tt: s, | |
u: s, | |
ul: s, | |
"var": s, | |
video: { | |
attrs: { | |
src: null, poster: null, width: null, height: null, | |
crossorigin: ["anonymous", "use-credentials"], | |
preload: ["auto", "metadata", "none"], | |
autoplay: ["", "autoplay"], | |
mediagroup: ["movie"], | |
muted: ["", "muted"], | |
controls: ["", "controls"] | |
} | |
}, | |
wbr: s | |
}; | |
var globalAttrs = { | |
accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], | |
"class": null, | |
contenteditable: ["true", "false"], | |
contextmenu: null, | |
dir: ["ltr", "rtl", "auto"], | |
draggable: ["true", "false", "auto"], | |
dropzone: ["copy", "move", "link", "string:", "file:"], | |
hidden: ["hidden"], | |
id: null, | |
inert: ["inert"], | |
itemid: null, | |
itemprop: null, | |
itemref: null, | |
itemscope: ["itemscope"], | |
itemtype: null, | |
lang: ["en", "es"], | |
spellcheck: ["true", "false"], | |
style: null, | |
tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"], | |
title: null, | |
translate: ["yes", "no"], | |
onclick: null, | |
rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"] | |
}; | |
function populate(obj) { | |
for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr)) | |
obj.attrs[attr] = globalAttrs[attr]; | |
} | |
populate(s); | |
for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s) | |
populate(data[tag]); | |
CodeMirror.htmlSchema = data; | |
function htmlHint(cm, options) { | |
var local = {schemaInfo: data}; | |
if (options) for (var opt in options) local[opt] = options[opt]; | |
return CodeMirror.hint.xml(cm, local); | |
} | |
CodeMirror.registerHelper("hint", "html", htmlHint); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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"), require("../../mode/sql/sql")); | |
else if (typeof define == "function" && define.amd) // AMD | |
define(["../../lib/codemirror", "../../mode/sql/sql"], mod); | |
else // Plain browser env | |
mod(CodeMirror); | |
})(function(CodeMirror) { | |
"use strict"; | |
var tables; | |
var defaultTable; | |
var keywords; | |
var CONS = { | |
QUERY_DIV: ";", | |
ALIAS_KEYWORD: "AS" | |
}; | |
var Pos = CodeMirror.Pos; | |
function getKeywords(editor) { | |
var mode = editor.doc.modeOption; | |
if (mode === "sql") mode = "text/x-sql"; | |
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 = getText(word).substr(0, len); | |
return string.toUpperCase() === sub.toUpperCase(); | |
} | |
function addMatches(result, search, wordlist, formatter) { | |
for (var word in wordlist) { | |
if (!wordlist.hasOwnProperty(word)) continue; | |
if (wordlist.slice) word = wordlist[word]; | |
if (match(search, word)) result.push(formatter(word)); | |
} | |
} | |
function cleanName(name) { | |
// Get rid name from backticks(`) and preceding dot(.) | |
if (name.charAt(0) == ".") { | |
name = name.substr(1); | |
} | |
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("."); | |
var alias = false; | |
var aliasTable = table; | |
// Check if table is available. If not, find table by Alias | |
if (!getItem(tables, table)) { | |
var oldTable = table; | |
table = findTableByAlias(table, editor); | |
if (table !== oldTable) alias = true; | |
} | |
var columns = getItem(tables, table); | |
if (columns && columns.columns) | |
columns = columns.columns; | |
if (columns) { | |
addMatches(result, string, columns, function(w) { | |
var tableInsert = table; | |
if (alias == true) tableInsert = aliasTable; | |
if (typeof w == "string") { | |
w = tableInsert + "." + w; | |
} else { | |
w = shallowClone(w); | |
w.text = tableInsert + "." + w.text; | |
} | |
return useBacktick ? insertBackticks(w) : w; | |
}); | |
} | |
return start; | |
} | |
function eachWord(lineText, f) { | |
if (!lineText) return; | |
var excepted = /[,;]/g; | |
var words = lineText.split(" "); | |
for (var i = 0; i < words.length; i++) { | |
f(words[i]?words[i].replace(excepted, '') : ''); | |
} | |
} | |
function convertCurToNumber(cur) { | |
// max characters of a line is 999,999. | |
return cur.line + cur.ch / Math.pow(10, 6); | |
} | |
function convertNumberToCur(num) { | |
return Pos(Math.floor(num), +num.toString().split('.').pop()); | |
} | |
function findTableByAlias(alias, editor) { | |
var doc = editor.doc; | |
var fullQuery = doc.getValue(); | |
var aliasUpperCase = alias.toUpperCase(); | |
var previousWord = ""; | |
var table = ""; | |
var separator = []; | |
var validRange = { | |
start: Pos(0, 0), | |
end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length) | |
}; | |
//add separator | |
var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV); | |
while(indexOfSeparator != -1) { | |
separator.push(doc.posFromIndex(indexOfSeparator)); | |
indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1); | |
} | |
separator.unshift(Pos(0, 0)); | |
separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length)); | |
//find valid range | |
var prevItem = 0; | |
var current = convertCurToNumber(editor.getCursor()); | |
for (var i=0; i< separator.length; i++) { | |
var _v = convertCurToNumber(separator[i]); | |
if (current > prevItem && current <= _v) { | |
validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) }; | |
break; | |
} | |
prevItem = _v; | |
} | |
var query = doc.getRange(validRange.start, validRange.end, false); | |
for (var i = 0; i < query.length; i++) { | |
var lineText = query[i]; | |
eachWord(lineText, function(word) { | |
var wordUpperCase = word.toUpperCase(); | |
if (wordUpperCase === aliasUpperCase && getItem(tables, previousWord)) | |
table = previousWord; | |
if (wordUpperCase !== CONS.ALIAS_KEYWORD) | |
previousWord = word; | |
}); | |
if (table) break; | |
} | |
return table; | |
} | |
CodeMirror.registerHelper("hint", "sql", function(editor, options) { | |
tables = (options && options.tables) || {}; | |
var defaultTableName = options && options.defaultTable; | |
var disableKeywords = options && options.disableKeywords; | |
defaultTable = defaultTableName && getItem(tables, defaultTableName); | |
keywords = keywords || getKeywords(editor); | |
if (defaultTableName && !defaultTable) | |
defaultTable = findTableByAlias(defaultTableName, editor); | |
defaultTable = defaultTable || []; | |
if (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; | |
end = token.end; | |
} else { | |
start = end = cur.ch; | |
search = ""; | |
} | |
if (search.charAt(0) == "." || search.charAt(0) == "`") { | |
start = nameCompletion(cur, token, result, editor); | |
} else { | |
addMatches(result, search, tables, function(w) {return w;}); | |
addMatches(result, search, defaultTable, function(w) {return w;}); | |
if (!disableKeywords) | |
addMatches(result, search, keywords, function(w) {return w.toUpperCase();}); | |
} | |
return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)}; | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment