Subversion-Projekte lars-tiefland.ci

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
776 lars 1
// CodeMirror, copyright (c) by Marijn Haverbeke and others
2
// Distributed under an MIT license: http://codemirror.net/LICENSE
3
 
4
(function(mod) {
5
  if (typeof exports == "object" && typeof module == "object") // CommonJS
6
    mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
7
  else if (typeof define == "function" && define.amd) // AMD
8
    define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
9
  else // Plain browser env
10
    mod(CodeMirror);
11
})(function(CodeMirror) {
12
  "use strict";
13
 
14
  var tables;
15
  var defaultTable;
16
  var keywords;
17
  var CONS = {
18
    QUERY_DIV: ";",
19
    ALIAS_KEYWORD: "AS"
20
  };
21
  var Pos = CodeMirror.Pos;
22
 
23
  function getKeywords(editor) {
24
    var mode = editor.doc.modeOption;
25
    if (mode === "sql") mode = "text/x-sql";
26
    return CodeMirror.resolveMode(mode).keywords;
27
  }
28
 
29
  function getText(item) {
30
    return typeof item == "string" ? item : item.text;
31
  }
32
 
33
  function getItem(list, item) {
34
    if (!list.slice) return list[item];
35
    for (var i = list.length - 1; i >= 0; i--) if (getText(list[i]) == item)
36
      return list[i];
37
  }
38
 
39
  function shallowClone(object) {
40
    var result = {};
41
    for (var key in object) if (object.hasOwnProperty(key))
42
      result[key] = object[key];
43
    return result;
44
  }
45
 
46
  function match(string, word) {
47
    var len = string.length;
48
    var sub = getText(word).substr(0, len);
49
    return string.toUpperCase() === sub.toUpperCase();
50
  }
51
 
52
  function addMatches(result, search, wordlist, formatter) {
53
    for (var word in wordlist) {
54
      if (!wordlist.hasOwnProperty(word)) continue;
55
      if (wordlist.slice) word = wordlist[word];
56
 
57
      if (match(search, word)) result.push(formatter(word));
58
    }
59
  }
60
 
61
  function cleanName(name) {
62
    // Get rid name from backticks(`) and preceding dot(.)
63
    if (name.charAt(0) == ".") {
64
      name = name.substr(1);
65
    }
66
    return name.replace(/`/g, "");
67
  }
68
 
69
  function insertBackticks(name) {
70
    var nameParts = getText(name).split(".");
71
    for (var i = 0; i < nameParts.length; i++)
72
      nameParts[i] = "`" + nameParts[i] + "`";
73
    var escaped = nameParts.join(".");
74
    if (typeof name == "string") return escaped;
75
    name = shallowClone(name);
76
    name.text = escaped;
77
    return name;
78
  }
79
 
80
  function nameCompletion(cur, token, result, editor) {
81
    // Try to complete table, colunm names and return start position of completion
82
    var useBacktick = false;
83
    var nameParts = [];
84
    var start = token.start;
85
    var cont = true;
86
    while (cont) {
87
      cont = (token.string.charAt(0) == ".");
88
      useBacktick = useBacktick || (token.string.charAt(0) == "`");
89
 
90
      start = token.start;
91
      nameParts.unshift(cleanName(token.string));
92
 
93
      token = editor.getTokenAt(Pos(cur.line, token.start));
94
      if (token.string == ".") {
95
        cont = true;
96
        token = editor.getTokenAt(Pos(cur.line, token.start));
97
      }
98
    }
99
 
100
    // Try to complete table names
101
    var string = nameParts.join(".");
102
    addMatches(result, string, tables, function(w) {
103
      return useBacktick ? insertBackticks(w) : w;
104
    });
105
 
106
    // Try to complete columns from defaultTable
107
    addMatches(result, string, defaultTable, function(w) {
108
      return useBacktick ? insertBackticks(w) : w;
109
    });
110
 
111
    // Try to complete columns
112
    string = nameParts.pop();
113
    var table = nameParts.join(".");
114
 
115
    var alias = false;
116
    var aliasTable = table;
117
    // Check if table is available. If not, find table by Alias
118
    if (!getItem(tables, table)) {
119
      var oldTable = table;
120
      table = findTableByAlias(table, editor);
121
      if (table !== oldTable) alias = true;
122
    }
123
 
124
    var columns = getItem(tables, table);
125
    if (columns && columns.columns)
126
      columns = columns.columns;
127
 
128
    if (columns) {
129
      addMatches(result, string, columns, function(w) {
130
        var tableInsert = table;
131
        if (alias == true) tableInsert = aliasTable;
132
        if (typeof w == "string") {
133
          w = tableInsert + "." + w;
134
        } else {
135
          w = shallowClone(w);
136
          w.text = tableInsert + "." + w.text;
137
        }
138
        return useBacktick ? insertBackticks(w) : w;
139
      });
140
    }
141
 
142
    return start;
143
  }
144
 
145
  function eachWord(lineText, f) {
146
    if (!lineText) return;
147
    var excepted = /[,;]/g;
148
    var words = lineText.split(" ");
149
    for (var i = 0; i < words.length; i++) {
150
      f(words[i]?words[i].replace(excepted, '') : '');
151
    }
152
  }
153
 
154
  function convertCurToNumber(cur) {
155
    // max characters of a line is 999,999.
156
    return cur.line + cur.ch / Math.pow(10, 6);
157
  }
158
 
159
  function convertNumberToCur(num) {
160
    return Pos(Math.floor(num), +num.toString().split('.').pop());
161
  }
162
 
163
  function findTableByAlias(alias, editor) {
164
    var doc = editor.doc;
165
    var fullQuery = doc.getValue();
166
    var aliasUpperCase = alias.toUpperCase();
167
    var previousWord = "";
168
    var table = "";
169
    var separator = [];
170
    var validRange = {
171
      start: Pos(0, 0),
172
      end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)
173
    };
174
 
175
    //add separator
176
    var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);
177
    while(indexOfSeparator != -1) {
178
      separator.push(doc.posFromIndex(indexOfSeparator));
179
      indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);
180
    }
181
    separator.unshift(Pos(0, 0));
182
    separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
183
 
184
    //find valid range
185
    var prevItem = 0;
186
    var current = convertCurToNumber(editor.getCursor());
187
    for (var i=0; i< separator.length; i++) {
188
      var _v = convertCurToNumber(separator[i]);
189
      if (current > prevItem && current <= _v) {
190
        validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) };
191
        break;
192
      }
193
      prevItem = _v;
194
    }
195
 
196
    var query = doc.getRange(validRange.start, validRange.end, false);
197
 
198
    for (var i = 0; i < query.length; i++) {
199
      var lineText = query[i];
200
      eachWord(lineText, function(word) {
201
        var wordUpperCase = word.toUpperCase();
202
        if (wordUpperCase === aliasUpperCase && getItem(tables, previousWord))
203
          table = previousWord;
204
        if (wordUpperCase !== CONS.ALIAS_KEYWORD)
205
          previousWord = word;
206
      });
207
      if (table) break;
208
    }
209
    return table;
210
  }
211
 
212
  CodeMirror.registerHelper("hint", "sql", function(editor, options) {
213
    tables = (options && options.tables) || {};
214
    var defaultTableName = options && options.defaultTable;
215
    var disableKeywords = options && options.disableKeywords;
216
    defaultTable = defaultTableName && getItem(tables, defaultTableName);
217
    keywords = keywords || getKeywords(editor);
218
 
219
    if (defaultTableName && !defaultTable)
220
      defaultTable = findTableByAlias(defaultTableName, editor);
221
 
222
    defaultTable = defaultTable || [];
223
 
224
    if (defaultTable.columns)
225
      defaultTable = defaultTable.columns;
226
 
227
    var cur = editor.getCursor();
228
    var result = [];
229
    var token = editor.getTokenAt(cur), start, end, search;
230
    if (token.end > cur.ch) {
231
      token.end = cur.ch;
232
      token.string = token.string.slice(0, cur.ch - token.start);
233
    }
234
 
235
    if (token.string.match(/^[.`\w@]\w*$/)) {
236
      search = token.string;
237
      start = token.start;
238
      end = token.end;
239
    } else {
240
      start = end = cur.ch;
241
      search = "";
242
    }
243
    if (search.charAt(0) == "." || search.charAt(0) == "`") {
244
      start = nameCompletion(cur, token, result, editor);
245
    } else {
246
      addMatches(result, search, tables, function(w) {return w;});
247
      addMatches(result, search, defaultTable, function(w) {return w;});
248
      if (!disableKeywords)
249
        addMatches(result, search, keywords, function(w) {return w.toUpperCase();});
250
    }
251
 
252
    return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
253
  });
254
});