corrade-nucleus-nucleons – Blame information for rev 24
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
20 | office | 1 | define("ace/snippets",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/lib/lang","ace/range","ace/anchor","ace/keyboard/hash_handler","ace/tokenizer","ace/lib/dom","ace/editor"], function(require, exports, module) { |
2 | "use strict"; |
||
3 | var oop = require("./lib/oop"); |
||
4 | var EventEmitter = require("./lib/event_emitter").EventEmitter; |
||
5 | var lang = require("./lib/lang"); |
||
6 | var Range = require("./range").Range; |
||
7 | var Anchor = require("./anchor").Anchor; |
||
8 | var HashHandler = require("./keyboard/hash_handler").HashHandler; |
||
9 | var Tokenizer = require("./tokenizer").Tokenizer; |
||
10 | var comparePoints = Range.comparePoints; |
||
11 | |||
12 | var SnippetManager = function() { |
||
13 | this.snippetMap = {}; |
||
14 | this.snippetNameMap = {}; |
||
15 | }; |
||
16 | |||
17 | (function() { |
||
18 | oop.implement(this, EventEmitter); |
||
19 | |||
20 | this.getTokenizer = function() { |
||
21 | function TabstopToken(str, _, stack) { |
||
22 | str = str.substr(1); |
||
23 | if (/^\d+$/.test(str) && !stack.inFormatString) |
||
24 | return [{tabstopId: parseInt(str, 10)}]; |
||
25 | return [{text: str}]; |
||
26 | } |
||
27 | function escape(ch) { |
||
28 | return "(?:[^\\\\" + ch + "]|\\\\.)"; |
||
29 | } |
||
30 | SnippetManager.$tokenizer = new Tokenizer({ |
||
31 | start: [ |
||
32 | {regex: /:/, onMatch: function(val, state, stack) { |
||
33 | if (stack.length && stack[0].expectIf) { |
||
34 | stack[0].expectIf = false; |
||
35 | stack[0].elseBranch = stack[0]; |
||
36 | return [stack[0]]; |
||
37 | } |
||
38 | return ":"; |
||
39 | }}, |
||
40 | {regex: /\\./, onMatch: function(val, state, stack) { |
||
41 | var ch = val[1]; |
||
42 | if (ch == "}" && stack.length) { |
||
43 | val = ch; |
||
44 | }else if ("`$\\".indexOf(ch) != -1) { |
||
45 | val = ch; |
||
46 | } else if (stack.inFormatString) { |
||
47 | if (ch == "n") |
||
48 | val = "\n"; |
||
49 | else if (ch == "t") |
||
50 | val = "\n"; |
||
51 | else if ("ulULE".indexOf(ch) != -1) { |
||
52 | val = {changeCase: ch, local: ch > "a"}; |
||
53 | } |
||
54 | } |
||
55 | |||
56 | return [val]; |
||
57 | }}, |
||
58 | {regex: /}/, onMatch: function(val, state, stack) { |
||
59 | return [stack.length ? stack.shift() : val]; |
||
60 | }}, |
||
61 | {regex: /\$(?:\d+|\w+)/, onMatch: TabstopToken}, |
||
62 | {regex: /\$\{[\dA-Z_a-z]+/, onMatch: function(str, state, stack) { |
||
63 | var t = TabstopToken(str.substr(1), state, stack); |
||
64 | stack.unshift(t[0]); |
||
65 | return t; |
||
66 | }, next: "snippetVar"}, |
||
67 | {regex: /\n/, token: "newline", merge: false} |
||
68 | ], |
||
69 | snippetVar: [ |
||
70 | {regex: "\\|" + escape("\\|") + "*\\|", onMatch: function(val, state, stack) { |
||
71 | stack[0].choices = val.slice(1, -1).split(","); |
||
72 | }, next: "start"}, |
||
73 | {regex: "/(" + escape("/") + "+)/(?:(" + escape("/") + "*)/)(\\w*):?", |
||
74 | onMatch: function(val, state, stack) { |
||
75 | var ts = stack[0]; |
||
76 | ts.fmtString = val; |
||
77 | |||
78 | val = this.splitRegex.exec(val); |
||
79 | ts.guard = val[1]; |
||
80 | ts.fmt = val[2]; |
||
81 | ts.flag = val[3]; |
||
82 | return ""; |
||
83 | }, next: "start"}, |
||
84 | {regex: "`" + escape("`") + "*`", onMatch: function(val, state, stack) { |
||
85 | stack[0].code = val.splice(1, -1); |
||
86 | return ""; |
||
87 | }, next: "start"}, |
||
88 | {regex: "\\?", onMatch: function(val, state, stack) { |
||
89 | if (stack[0]) |
||
90 | stack[0].expectIf = true; |
||
91 | }, next: "start"}, |
||
92 | {regex: "([^:}\\\\]|\\\\.)*:?", token: "", next: "start"} |
||
93 | ], |
||
94 | formatString: [ |
||
95 | {regex: "/(" + escape("/") + "+)/", token: "regex"}, |
||
96 | {regex: "", onMatch: function(val, state, stack) { |
||
97 | stack.inFormatString = true; |
||
98 | }, next: "start"} |
||
99 | ] |
||
100 | }); |
||
101 | SnippetManager.prototype.getTokenizer = function() { |
||
102 | return SnippetManager.$tokenizer; |
||
103 | }; |
||
104 | return SnippetManager.$tokenizer; |
||
105 | }; |
||
106 | |||
107 | this.tokenizeTmSnippet = function(str, startState) { |
||
108 | return this.getTokenizer().getLineTokens(str, startState).tokens.map(function(x) { |
||
109 | return x.value || x; |
||
110 | }); |
||
111 | }; |
||
112 | |||
113 | this.$getDefaultValue = function(editor, name) { |
||
114 | if (/^[A-Z]\d+$/.test(name)) { |
||
115 | var i = name.substr(1); |
||
116 | return (this.variables[name[0] + "__"] || {})[i]; |
||
117 | } |
||
118 | if (/^\d+$/.test(name)) { |
||
119 | return (this.variables.__ || {})[name]; |
||
120 | } |
||
121 | name = name.replace(/^TM_/, ""); |
||
122 | |||
123 | if (!editor) |
||
124 | return; |
||
125 | var s = editor.session; |
||
126 | switch(name) { |
||
127 | case "CURRENT_WORD": |
||
128 | var r = s.getWordRange(); |
||
129 | case "SELECTION": |
||
130 | case "SELECTED_TEXT": |
||
131 | return s.getTextRange(r); |
||
132 | case "CURRENT_LINE": |
||
133 | return s.getLine(editor.getCursorPosition().row); |
||
134 | case "PREV_LINE": // not possible in textmate |
||
135 | return s.getLine(editor.getCursorPosition().row - 1); |
||
136 | case "LINE_INDEX": |
||
137 | return editor.getCursorPosition().column; |
||
138 | case "LINE_NUMBER": |
||
139 | return editor.getCursorPosition().row + 1; |
||
140 | case "SOFT_TABS": |
||
141 | return s.getUseSoftTabs() ? "YES" : "NO"; |
||
142 | case "TAB_SIZE": |
||
143 | return s.getTabSize(); |
||
144 | case "FILENAME": |
||
145 | case "FILEPATH": |
||
146 | return ""; |
||
147 | case "FULLNAME": |
||
148 | return "Ace"; |
||
149 | } |
||
150 | }; |
||
151 | this.variables = {}; |
||
152 | this.getVariableValue = function(editor, varName) { |
||
153 | if (this.variables.hasOwnProperty(varName)) |
||
154 | return this.variables[varName](editor, varName) || ""; |
||
155 | return this.$getDefaultValue(editor, varName) || ""; |
||
156 | }; |
||
157 | this.tmStrFormat = function(str, ch, editor) { |
||
158 | var flag = ch.flag || ""; |
||
159 | var re = ch.guard; |
||
160 | re = new RegExp(re, flag.replace(/[^gi]/, "")); |
||
161 | var fmtTokens = this.tokenizeTmSnippet(ch.fmt, "formatString"); |
||
162 | var _self = this; |
||
163 | var formatted = str.replace(re, function() { |
||
164 | _self.variables.__ = arguments; |
||
165 | var fmtParts = _self.resolveVariables(fmtTokens, editor); |
||
166 | var gChangeCase = "E"; |
||
167 | for (var i = 0; i < fmtParts.length; i++) { |
||
168 | var ch = fmtParts[i]; |
||
169 | if (typeof ch == "object") { |
||
170 | fmtParts[i] = ""; |
||
171 | if (ch.changeCase && ch.local) { |
||
172 | var next = fmtParts[i + 1]; |
||
173 | if (next && typeof next == "string") { |
||
174 | if (ch.changeCase == "u") |
||
175 | fmtParts[i] = next[0].toUpperCase(); |
||
176 | else |
||
177 | fmtParts[i] = next[0].toLowerCase(); |
||
178 | fmtParts[i + 1] = next.substr(1); |
||
179 | } |
||
180 | } else if (ch.changeCase) { |
||
181 | gChangeCase = ch.changeCase; |
||
182 | } |
||
183 | } else if (gChangeCase == "U") { |
||
184 | fmtParts[i] = ch.toUpperCase(); |
||
185 | } else if (gChangeCase == "L") { |
||
186 | fmtParts[i] = ch.toLowerCase(); |
||
187 | } |
||
188 | } |
||
189 | return fmtParts.join(""); |
||
190 | }); |
||
191 | this.variables.__ = null; |
||
192 | return formatted; |
||
193 | }; |
||
194 | |||
195 | this.resolveVariables = function(snippet, editor) { |
||
196 | var result = []; |
||
197 | for (var i = 0; i < snippet.length; i++) { |
||
198 | var ch = snippet[i]; |
||
199 | if (typeof ch == "string") { |
||
200 | result.push(ch); |
||
201 | } else if (typeof ch != "object") { |
||
202 | continue; |
||
203 | } else if (ch.skip) { |
||
204 | gotoNext(ch); |
||
205 | } else if (ch.processed < i) { |
||
206 | continue; |
||
207 | } else if (ch.text) { |
||
208 | var value = this.getVariableValue(editor, ch.text); |
||
209 | if (value && ch.fmtString) |
||
210 | value = this.tmStrFormat(value, ch); |
||
211 | ch.processed = i; |
||
212 | if (ch.expectIf == null) { |
||
213 | if (value) { |
||
214 | result.push(value); |
||
215 | gotoNext(ch); |
||
216 | } |
||
217 | } else { |
||
218 | if (value) { |
||
219 | ch.skip = ch.elseBranch; |
||
220 | } else |
||
221 | gotoNext(ch); |
||
222 | } |
||
223 | } else if (ch.tabstopId != null) { |
||
224 | result.push(ch); |
||
225 | } else if (ch.changeCase != null) { |
||
226 | result.push(ch); |
||
227 | } |
||
228 | } |
||
229 | function gotoNext(ch) { |
||
230 | var i1 = snippet.indexOf(ch, i + 1); |
||
231 | if (i1 != -1) |
||
232 | i = i1; |
||
233 | } |
||
234 | return result; |
||
235 | }; |
||
236 | |||
237 | this.insertSnippetForSelection = function(editor, snippetText) { |
||
238 | var cursor = editor.getCursorPosition(); |
||
239 | var line = editor.session.getLine(cursor.row); |
||
240 | var tabString = editor.session.getTabString(); |
||
241 | var indentString = line.match(/^\s*/)[0]; |
||
242 | |||
243 | if (cursor.column < indentString.length) |
||
244 | indentString = indentString.slice(0, cursor.column); |
||
245 | |||
246 | snippetText = snippetText.replace(/\r/g, ""); |
||
247 | var tokens = this.tokenizeTmSnippet(snippetText); |
||
248 | tokens = this.resolveVariables(tokens, editor); |
||
249 | tokens = tokens.map(function(x) { |
||
250 | if (x == "\n") |
||
251 | return x + indentString; |
||
252 | if (typeof x == "string") |
||
253 | return x.replace(/\t/g, tabString); |
||
254 | return x; |
||
255 | }); |
||
256 | var tabstops = []; |
||
257 | tokens.forEach(function(p, i) { |
||
258 | if (typeof p != "object") |
||
259 | return; |
||
260 | var id = p.tabstopId; |
||
261 | var ts = tabstops[id]; |
||
262 | if (!ts) { |
||
263 | ts = tabstops[id] = []; |
||
264 | ts.index = id; |
||
265 | ts.value = ""; |
||
266 | } |
||
267 | if (ts.indexOf(p) !== -1) |
||
268 | return; |
||
269 | ts.push(p); |
||
270 | var i1 = tokens.indexOf(p, i + 1); |
||
271 | if (i1 === -1) |
||
272 | return; |
||
273 | |||
274 | var value = tokens.slice(i + 1, i1); |
||
275 | var isNested = value.some(function(t) {return typeof t === "object"}); |
||
276 | if (isNested && !ts.value) { |
||
277 | ts.value = value; |
||
278 | } else if (value.length && (!ts.value || typeof ts.value !== "string")) { |
||
279 | ts.value = value.join(""); |
||
280 | } |
||
281 | }); |
||
282 | tabstops.forEach(function(ts) {ts.length = 0}); |
||
283 | var expanding = {}; |
||
284 | function copyValue(val) { |
||
285 | var copy = []; |
||
286 | for (var i = 0; i < val.length; i++) { |
||
287 | var p = val[i]; |
||
288 | if (typeof p == "object") { |
||
289 | if (expanding[p.tabstopId]) |
||
290 | continue; |
||
291 | var j = val.lastIndexOf(p, i - 1); |
||
292 | p = copy[j] || {tabstopId: p.tabstopId}; |
||
293 | } |
||
294 | copy[i] = p; |
||
295 | } |
||
296 | return copy; |
||
297 | } |
||
298 | for (var i = 0; i < tokens.length; i++) { |
||
299 | var p = tokens[i]; |
||
300 | if (typeof p != "object") |
||
301 | continue; |
||
302 | var id = p.tabstopId; |
||
303 | var i1 = tokens.indexOf(p, i + 1); |
||
304 | if (expanding[id]) { |
||
305 | if (expanding[id] === p) |
||
306 | expanding[id] = null; |
||
307 | continue; |
||
308 | } |
||
309 | |||
310 | var ts = tabstops[id]; |
||
311 | var arg = typeof ts.value == "string" ? [ts.value] : copyValue(ts.value); |
||
312 | arg.unshift(i + 1, Math.max(0, i1 - i)); |
||
313 | arg.push(p); |
||
314 | expanding[id] = p; |
||
315 | tokens.splice.apply(tokens, arg); |
||
316 | |||
317 | if (ts.indexOf(p) === -1) |
||
318 | ts.push(p); |
||
319 | } |
||
320 | var row = 0, column = 0; |
||
321 | var text = ""; |
||
322 | tokens.forEach(function(t) { |
||
323 | if (typeof t === "string") { |
||
324 | var lines = t.split("\n"); |
||
325 | if (lines.length > 1){ |
||
326 | column = lines[lines.length - 1].length; |
||
327 | row += lines.length - 1; |
||
328 | } else |
||
329 | column += t.length; |
||
330 | text += t; |
||
331 | } else { |
||
332 | if (!t.start) |
||
333 | t.start = {row: row, column: column}; |
||
334 | else |
||
335 | t.end = {row: row, column: column}; |
||
336 | } |
||
337 | }); |
||
338 | var range = editor.getSelectionRange(); |
||
339 | var end = editor.session.replace(range, text); |
||
340 | |||
341 | var tabstopManager = new TabstopManager(editor); |
||
342 | var selectionId = editor.inVirtualSelectionMode && editor.selection.index; |
||
343 | tabstopManager.addTabstops(tabstops, range.start, end, selectionId); |
||
344 | }; |
||
345 | |||
346 | this.insertSnippet = function(editor, snippetText) { |
||
347 | var self = this; |
||
348 | if (editor.inVirtualSelectionMode) |
||
349 | return self.insertSnippetForSelection(editor, snippetText); |
||
350 | |||
351 | editor.forEachSelection(function() { |
||
352 | self.insertSnippetForSelection(editor, snippetText); |
||
353 | }, null, {keepOrder: true}); |
||
354 | |||
355 | if (editor.tabstopManager) |
||
356 | editor.tabstopManager.tabNext(); |
||
357 | }; |
||
358 | |||
359 | this.$getScope = function(editor) { |
||
360 | var scope = editor.session.$mode.$id || ""; |
||
361 | scope = scope.split("/").pop(); |
||
362 | if (scope === "html" || scope === "php") { |
||
363 | if (scope === "php" && !editor.session.$mode.inlinePhp) |
||
364 | scope = "html"; |
||
365 | var c = editor.getCursorPosition(); |
||
366 | var state = editor.session.getState(c.row); |
||
367 | if (typeof state === "object") { |
||
368 | state = state[0]; |
||
369 | } |
||
370 | if (state.substring) { |
||
371 | if (state.substring(0, 3) == "js-") |
||
372 | scope = "javascript"; |
||
373 | else if (state.substring(0, 4) == "css-") |
||
374 | scope = "css"; |
||
375 | else if (state.substring(0, 4) == "php-") |
||
376 | scope = "php"; |
||
377 | } |
||
378 | } |
||
379 | |||
380 | return scope; |
||
381 | }; |
||
382 | |||
383 | this.getActiveScopes = function(editor) { |
||
384 | var scope = this.$getScope(editor); |
||
385 | var scopes = [scope]; |
||
386 | var snippetMap = this.snippetMap; |
||
387 | if (snippetMap[scope] && snippetMap[scope].includeScopes) { |
||
388 | scopes.push.apply(scopes, snippetMap[scope].includeScopes); |
||
389 | } |
||
390 | scopes.push("_"); |
||
391 | return scopes; |
||
392 | }; |
||
393 | |||
394 | this.expandWithTab = function(editor, options) { |
||
395 | var self = this; |
||
396 | var result = editor.forEachSelection(function() { |
||
397 | return self.expandSnippetForSelection(editor, options); |
||
398 | }, null, {keepOrder: true}); |
||
399 | if (result && editor.tabstopManager) |
||
400 | editor.tabstopManager.tabNext(); |
||
401 | return result; |
||
402 | }; |
||
403 | |||
404 | this.expandSnippetForSelection = function(editor, options) { |
||
405 | var cursor = editor.getCursorPosition(); |
||
406 | var line = editor.session.getLine(cursor.row); |
||
407 | var before = line.substring(0, cursor.column); |
||
408 | var after = line.substr(cursor.column); |
||
409 | |||
410 | var snippetMap = this.snippetMap; |
||
411 | var snippet; |
||
412 | this.getActiveScopes(editor).some(function(scope) { |
||
413 | var snippets = snippetMap[scope]; |
||
414 | if (snippets) |
||
415 | snippet = this.findMatchingSnippet(snippets, before, after); |
||
416 | return !!snippet; |
||
417 | }, this); |
||
418 | if (!snippet) |
||
419 | return false; |
||
420 | if (options && options.dryRun) |
||
421 | return true; |
||
422 | editor.session.doc.removeInLine(cursor.row, |
||
423 | cursor.column - snippet.replaceBefore.length, |
||
424 | cursor.column + snippet.replaceAfter.length |
||
425 | ); |
||
426 | |||
427 | this.variables.M__ = snippet.matchBefore; |
||
428 | this.variables.T__ = snippet.matchAfter; |
||
429 | this.insertSnippetForSelection(editor, snippet.content); |
||
430 | |||
431 | this.variables.M__ = this.variables.T__ = null; |
||
432 | return true; |
||
433 | }; |
||
434 | |||
435 | this.findMatchingSnippet = function(snippetList, before, after) { |
||
436 | for (var i = snippetList.length; i--;) { |
||
437 | var s = snippetList[i]; |
||
438 | if (s.startRe && !s.startRe.test(before)) |
||
439 | continue; |
||
440 | if (s.endRe && !s.endRe.test(after)) |
||
441 | continue; |
||
442 | if (!s.startRe && !s.endRe) |
||
443 | continue; |
||
444 | |||
445 | s.matchBefore = s.startRe ? s.startRe.exec(before) : [""]; |
||
446 | s.matchAfter = s.endRe ? s.endRe.exec(after) : [""]; |
||
447 | s.replaceBefore = s.triggerRe ? s.triggerRe.exec(before)[0] : ""; |
||
448 | s.replaceAfter = s.endTriggerRe ? s.endTriggerRe.exec(after)[0] : ""; |
||
449 | return s; |
||
450 | } |
||
451 | }; |
||
452 | |||
453 | this.snippetMap = {}; |
||
454 | this.snippetNameMap = {}; |
||
455 | this.register = function(snippets, scope) { |
||
456 | var snippetMap = this.snippetMap; |
||
457 | var snippetNameMap = this.snippetNameMap; |
||
458 | var self = this; |
||
459 | |||
460 | if (!snippets) |
||
461 | snippets = []; |
||
462 | |||
463 | function wrapRegexp(src) { |
||
464 | if (src && !/^\^?\(.*\)\$?$|^\\b$/.test(src)) |
||
465 | src = "(?:" + src + ")"; |
||
466 | |||
467 | return src || ""; |
||
468 | } |
||
469 | function guardedRegexp(re, guard, opening) { |
||
470 | re = wrapRegexp(re); |
||
471 | guard = wrapRegexp(guard); |
||
472 | if (opening) { |
||
473 | re = guard + re; |
||
474 | if (re && re[re.length - 1] != "$") |
||
475 | re = re + "$"; |
||
476 | } else { |
||
477 | re = re + guard; |
||
478 | if (re && re[0] != "^") |
||
479 | re = "^" + re; |
||
480 | } |
||
481 | return new RegExp(re); |
||
482 | } |
||
483 | |||
484 | function addSnippet(s) { |
||
485 | if (!s.scope) |
||
486 | s.scope = scope || "_"; |
||
487 | scope = s.scope; |
||
488 | if (!snippetMap[scope]) { |
||
489 | snippetMap[scope] = []; |
||
490 | snippetNameMap[scope] = {}; |
||
491 | } |
||
492 | |||
493 | var map = snippetNameMap[scope]; |
||
494 | if (s.name) { |
||
495 | var old = map[s.name]; |
||
496 | if (old) |
||
497 | self.unregister(old); |
||
498 | map[s.name] = s; |
||
499 | } |
||
500 | snippetMap[scope].push(s); |
||
501 | |||
502 | if (s.tabTrigger && !s.trigger) { |
||
503 | if (!s.guard && /^\w/.test(s.tabTrigger)) |
||
504 | s.guard = "\\b"; |
||
505 | s.trigger = lang.escapeRegExp(s.tabTrigger); |
||
506 | } |
||
507 | |||
508 | if (!s.trigger && !s.guard && !s.endTrigger && !s.endGuard) |
||
509 | return; |
||
510 | |||
511 | s.startRe = guardedRegexp(s.trigger, s.guard, true); |
||
512 | s.triggerRe = new RegExp(s.trigger, "", true); |
||
513 | |||
514 | s.endRe = guardedRegexp(s.endTrigger, s.endGuard, true); |
||
515 | s.endTriggerRe = new RegExp(s.endTrigger, "", true); |
||
516 | } |
||
517 | |||
518 | if (snippets && snippets.content) |
||
519 | addSnippet(snippets); |
||
520 | else if (Array.isArray(snippets)) |
||
521 | snippets.forEach(addSnippet); |
||
522 | |||
523 | this._signal("registerSnippets", {scope: scope}); |
||
524 | }; |
||
525 | this.unregister = function(snippets, scope) { |
||
526 | var snippetMap = this.snippetMap; |
||
527 | var snippetNameMap = this.snippetNameMap; |
||
528 | |||
529 | function removeSnippet(s) { |
||
530 | var nameMap = snippetNameMap[s.scope||scope]; |
||
531 | if (nameMap && nameMap[s.name]) { |
||
532 | delete nameMap[s.name]; |
||
533 | var map = snippetMap[s.scope||scope]; |
||
534 | var i = map && map.indexOf(s); |
||
535 | if (i >= 0) |
||
536 | map.splice(i, 1); |
||
537 | } |
||
538 | } |
||
539 | if (snippets.content) |
||
540 | removeSnippet(snippets); |
||
541 | else if (Array.isArray(snippets)) |
||
542 | snippets.forEach(removeSnippet); |
||
543 | }; |
||
544 | this.parseSnippetFile = function(str) { |
||
545 | str = str.replace(/\r/g, ""); |
||
546 | var list = [], snippet = {}; |
||
547 | var re = /^#.*|^({[\s\S]*})\s*$|^(\S+) (.*)$|^((?:\n*\t.*)+)/gm; |
||
548 | var m; |
||
549 | while (m = re.exec(str)) { |
||
550 | if (m[1]) { |
||
551 | try { |
||
552 | snippet = JSON.parse(m[1]); |
||
553 | list.push(snippet); |
||
554 | } catch (e) {} |
||
555 | } if (m[4]) { |
||
556 | snippet.content = m[4].replace(/^\t/gm, ""); |
||
557 | list.push(snippet); |
||
558 | snippet = {}; |
||
559 | } else { |
||
560 | var key = m[2], val = m[3]; |
||
561 | if (key == "regex") { |
||
562 | var guardRe = /\/((?:[^\/\\]|\\.)*)|$/g; |
||
563 | snippet.guard = guardRe.exec(val)[1]; |
||
564 | snippet.trigger = guardRe.exec(val)[1]; |
||
565 | snippet.endTrigger = guardRe.exec(val)[1]; |
||
566 | snippet.endGuard = guardRe.exec(val)[1]; |
||
567 | } else if (key == "snippet") { |
||
568 | snippet.tabTrigger = val.match(/^\S*/)[0]; |
||
569 | if (!snippet.name) |
||
570 | snippet.name = val; |
||
571 | } else { |
||
572 | snippet[key] = val; |
||
573 | } |
||
574 | } |
||
575 | } |
||
576 | return list; |
||
577 | }; |
||
578 | this.getSnippetByName = function(name, editor) { |
||
579 | var snippetMap = this.snippetNameMap; |
||
580 | var snippet; |
||
581 | this.getActiveScopes(editor).some(function(scope) { |
||
582 | var snippets = snippetMap[scope]; |
||
583 | if (snippets) |
||
584 | snippet = snippets[name]; |
||
585 | return !!snippet; |
||
586 | }, this); |
||
587 | return snippet; |
||
588 | }; |
||
589 | |||
590 | }).call(SnippetManager.prototype); |
||
591 | |||
592 | |||
593 | var TabstopManager = function(editor) { |
||
594 | if (editor.tabstopManager) |
||
595 | return editor.tabstopManager; |
||
596 | editor.tabstopManager = this; |
||
597 | this.$onChange = this.onChange.bind(this); |
||
598 | this.$onChangeSelection = lang.delayedCall(this.onChangeSelection.bind(this)).schedule; |
||
599 | this.$onChangeSession = this.onChangeSession.bind(this); |
||
600 | this.$onAfterExec = this.onAfterExec.bind(this); |
||
601 | this.attach(editor); |
||
602 | }; |
||
603 | (function() { |
||
604 | this.attach = function(editor) { |
||
605 | this.index = 0; |
||
606 | this.ranges = []; |
||
607 | this.tabstops = []; |
||
608 | this.$openTabstops = null; |
||
609 | this.selectedTabstop = null; |
||
610 | |||
611 | this.editor = editor; |
||
612 | this.editor.on("change", this.$onChange); |
||
613 | this.editor.on("changeSelection", this.$onChangeSelection); |
||
614 | this.editor.on("changeSession", this.$onChangeSession); |
||
615 | this.editor.commands.on("afterExec", this.$onAfterExec); |
||
616 | this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); |
||
617 | }; |
||
618 | this.detach = function() { |
||
619 | this.tabstops.forEach(this.removeTabstopMarkers, this); |
||
620 | this.ranges = null; |
||
621 | this.tabstops = null; |
||
622 | this.selectedTabstop = null; |
||
623 | this.editor.removeListener("change", this.$onChange); |
||
624 | this.editor.removeListener("changeSelection", this.$onChangeSelection); |
||
625 | this.editor.removeListener("changeSession", this.$onChangeSession); |
||
626 | this.editor.commands.removeListener("afterExec", this.$onAfterExec); |
||
627 | this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler); |
||
628 | this.editor.tabstopManager = null; |
||
629 | this.editor = null; |
||
630 | }; |
||
631 | |||
632 | this.onChange = function(delta) { |
||
633 | var changeRange = delta; |
||
634 | var isRemove = delta.action[0] == "r"; |
||
635 | var start = delta.start; |
||
636 | var end = delta.end; |
||
637 | var startRow = start.row; |
||
638 | var endRow = end.row; |
||
639 | var lineDif = endRow - startRow; |
||
640 | var colDiff = end.column - start.column; |
||
641 | |||
642 | if (isRemove) { |
||
643 | lineDif = -lineDif; |
||
644 | colDiff = -colDiff; |
||
645 | } |
||
646 | if (!this.$inChange && isRemove) { |
||
647 | var ts = this.selectedTabstop; |
||
648 | var changedOutside = ts && !ts.some(function(r) { |
||
649 | return comparePoints(r.start, start) <= 0 && comparePoints(r.end, end) >= 0; |
||
650 | }); |
||
651 | if (changedOutside) |
||
652 | return this.detach(); |
||
653 | } |
||
654 | var ranges = this.ranges; |
||
655 | for (var i = 0; i < ranges.length; i++) { |
||
656 | var r = ranges[i]; |
||
657 | if (r.end.row < start.row) |
||
658 | continue; |
||
659 | |||
660 | if (isRemove && comparePoints(start, r.start) < 0 && comparePoints(end, r.end) > 0) { |
||
661 | this.removeRange(r); |
||
662 | i--; |
||
663 | continue; |
||
664 | } |
||
665 | |||
666 | if (r.start.row == startRow && r.start.column > start.column) |
||
667 | r.start.column += colDiff; |
||
668 | if (r.end.row == startRow && r.end.column >= start.column) |
||
669 | r.end.column += colDiff; |
||
670 | if (r.start.row >= startRow) |
||
671 | r.start.row += lineDif; |
||
672 | if (r.end.row >= startRow) |
||
673 | r.end.row += lineDif; |
||
674 | |||
675 | if (comparePoints(r.start, r.end) > 0) |
||
676 | this.removeRange(r); |
||
677 | } |
||
678 | if (!ranges.length) |
||
679 | this.detach(); |
||
680 | }; |
||
681 | this.updateLinkedFields = function() { |
||
682 | var ts = this.selectedTabstop; |
||
683 | if (!ts || !ts.hasLinkedRanges) |
||
684 | return; |
||
685 | this.$inChange = true; |
||
686 | var session = this.editor.session; |
||
687 | var text = session.getTextRange(ts.firstNonLinked); |
||
688 | for (var i = ts.length; i--;) { |
||
689 | var range = ts[i]; |
||
690 | if (!range.linked) |
||
691 | continue; |
||
692 | var fmt = exports.snippetManager.tmStrFormat(text, range.original); |
||
693 | session.replace(range, fmt); |
||
694 | } |
||
695 | this.$inChange = false; |
||
696 | }; |
||
697 | this.onAfterExec = function(e) { |
||
698 | if (e.command && !e.command.readOnly) |
||
699 | this.updateLinkedFields(); |
||
700 | }; |
||
701 | this.onChangeSelection = function() { |
||
702 | if (!this.editor) |
||
703 | return; |
||
704 | var lead = this.editor.selection.lead; |
||
705 | var anchor = this.editor.selection.anchor; |
||
706 | var isEmpty = this.editor.selection.isEmpty(); |
||
707 | for (var i = this.ranges.length; i--;) { |
||
708 | if (this.ranges[i].linked) |
||
709 | continue; |
||
710 | var containsLead = this.ranges[i].contains(lead.row, lead.column); |
||
711 | var containsAnchor = isEmpty || this.ranges[i].contains(anchor.row, anchor.column); |
||
712 | if (containsLead && containsAnchor) |
||
713 | return; |
||
714 | } |
||
715 | this.detach(); |
||
716 | }; |
||
717 | this.onChangeSession = function() { |
||
718 | this.detach(); |
||
719 | }; |
||
720 | this.tabNext = function(dir) { |
||
721 | var max = this.tabstops.length; |
||
722 | var index = this.index + (dir || 1); |
||
723 | index = Math.min(Math.max(index, 1), max); |
||
724 | if (index == max) |
||
725 | index = 0; |
||
726 | this.selectTabstop(index); |
||
727 | if (index === 0) |
||
728 | this.detach(); |
||
729 | }; |
||
730 | this.selectTabstop = function(index) { |
||
731 | this.$openTabstops = null; |
||
732 | var ts = this.tabstops[this.index]; |
||
733 | if (ts) |
||
734 | this.addTabstopMarkers(ts); |
||
735 | this.index = index; |
||
736 | ts = this.tabstops[this.index]; |
||
737 | if (!ts || !ts.length) |
||
738 | return; |
||
739 | |||
740 | this.selectedTabstop = ts; |
||
741 | if (!this.editor.inVirtualSelectionMode) { |
||
742 | var sel = this.editor.multiSelect; |
||
743 | sel.toSingleRange(ts.firstNonLinked.clone()); |
||
744 | for (var i = ts.length; i--;) { |
||
745 | if (ts.hasLinkedRanges && ts[i].linked) |
||
746 | continue; |
||
747 | sel.addRange(ts[i].clone(), true); |
||
748 | } |
||
749 | if (sel.ranges[0]) |
||
750 | sel.addRange(sel.ranges[0].clone()); |
||
751 | } else { |
||
752 | this.editor.selection.setRange(ts.firstNonLinked); |
||
753 | } |
||
754 | |||
755 | this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler); |
||
756 | }; |
||
757 | this.addTabstops = function(tabstops, start, end) { |
||
758 | if (!this.$openTabstops) |
||
759 | this.$openTabstops = []; |
||
760 | if (!tabstops[0]) { |
||
761 | var p = Range.fromPoints(end, end); |
||
762 | moveRelative(p.start, start); |
||
763 | moveRelative(p.end, start); |
||
764 | tabstops[0] = [p]; |
||
765 | tabstops[0].index = 0; |
||
766 | } |
||
767 | |||
768 | var i = this.index; |
||
769 | var arg = [i + 1, 0]; |
||
770 | var ranges = this.ranges; |
||
771 | tabstops.forEach(function(ts, index) { |
||
772 | var dest = this.$openTabstops[index] || ts; |
||
773 | |||
774 | for (var i = ts.length; i--;) { |
||
775 | var p = ts[i]; |
||
776 | var range = Range.fromPoints(p.start, p.end || p.start); |
||
777 | movePoint(range.start, start); |
||
778 | movePoint(range.end, start); |
||
779 | range.original = p; |
||
780 | range.tabstop = dest; |
||
781 | ranges.push(range); |
||
782 | if (dest != ts) |
||
783 | dest.unshift(range); |
||
784 | else |
||
785 | dest[i] = range; |
||
786 | if (p.fmtString) { |
||
787 | range.linked = true; |
||
788 | dest.hasLinkedRanges = true; |
||
789 | } else if (!dest.firstNonLinked) |
||
790 | dest.firstNonLinked = range; |
||
791 | } |
||
792 | if (!dest.firstNonLinked) |
||
793 | dest.hasLinkedRanges = false; |
||
794 | if (dest === ts) { |
||
795 | arg.push(dest); |
||
796 | this.$openTabstops[index] = dest; |
||
797 | } |
||
798 | this.addTabstopMarkers(dest); |
||
799 | }, this); |
||
800 | |||
801 | if (arg.length > 2) { |
||
802 | if (this.tabstops.length) |
||
803 | arg.push(arg.splice(2, 1)[0]); |
||
804 | this.tabstops.splice.apply(this.tabstops, arg); |
||
805 | } |
||
806 | }; |
||
807 | |||
808 | this.addTabstopMarkers = function(ts) { |
||
809 | var session = this.editor.session; |
||
810 | ts.forEach(function(range) { |
||
811 | if (!range.markerId) |
||
812 | range.markerId = session.addMarker(range, "ace_snippet-marker", "text"); |
||
813 | }); |
||
814 | }; |
||
815 | this.removeTabstopMarkers = function(ts) { |
||
816 | var session = this.editor.session; |
||
817 | ts.forEach(function(range) { |
||
818 | session.removeMarker(range.markerId); |
||
819 | range.markerId = null; |
||
820 | }); |
||
821 | }; |
||
822 | this.removeRange = function(range) { |
||
823 | var i = range.tabstop.indexOf(range); |
||
824 | range.tabstop.splice(i, 1); |
||
825 | i = this.ranges.indexOf(range); |
||
826 | this.ranges.splice(i, 1); |
||
827 | this.editor.session.removeMarker(range.markerId); |
||
828 | if (!range.tabstop.length) { |
||
829 | i = this.tabstops.indexOf(range.tabstop); |
||
830 | if (i != -1) |
||
831 | this.tabstops.splice(i, 1); |
||
832 | if (!this.tabstops.length) |
||
833 | this.detach(); |
||
834 | } |
||
835 | }; |
||
836 | |||
837 | this.keyboardHandler = new HashHandler(); |
||
838 | this.keyboardHandler.bindKeys({ |
||
839 | "Tab": function(ed) { |
||
840 | if (exports.snippetManager && exports.snippetManager.expandWithTab(ed)) { |
||
841 | return; |
||
842 | } |
||
843 | |||
844 | ed.tabstopManager.tabNext(1); |
||
845 | }, |
||
846 | "Shift-Tab": function(ed) { |
||
847 | ed.tabstopManager.tabNext(-1); |
||
848 | }, |
||
849 | "Esc": function(ed) { |
||
850 | ed.tabstopManager.detach(); |
||
851 | }, |
||
852 | "Return": function(ed) { |
||
853 | return false; |
||
854 | } |
||
855 | }); |
||
856 | }).call(TabstopManager.prototype); |
||
857 | |||
858 | |||
859 | |||
860 | var changeTracker = {}; |
||
861 | changeTracker.onChange = Anchor.prototype.onChange; |
||
862 | changeTracker.setPosition = function(row, column) { |
||
863 | this.pos.row = row; |
||
864 | this.pos.column = column; |
||
865 | }; |
||
866 | changeTracker.update = function(pos, delta, $insertRight) { |
||
867 | this.$insertRight = $insertRight; |
||
868 | this.pos = pos; |
||
869 | this.onChange(delta); |
||
870 | }; |
||
871 | |||
872 | var movePoint = function(point, diff) { |
||
873 | if (point.row == 0) |
||
874 | point.column += diff.column; |
||
875 | point.row += diff.row; |
||
876 | }; |
||
877 | |||
878 | var moveRelative = function(point, start) { |
||
879 | if (point.row == start.row) |
||
880 | point.column -= start.column; |
||
881 | point.row -= start.row; |
||
882 | }; |
||
883 | |||
884 | |||
885 | require("./lib/dom").importCssString("\ |
||
886 | .ace_snippet-marker {\ |
||
887 | -moz-box-sizing: border-box;\ |
||
888 | box-sizing: border-box;\ |
||
889 | background: rgba(194, 193, 208, 0.09);\ |
||
890 | border: 1px dotted rgba(211, 208, 235, 0.62);\ |
||
891 | position: absolute;\ |
||
892 | }"); |
||
893 | |||
894 | exports.snippetManager = new SnippetManager(); |
||
895 | |||
896 | |||
897 | var Editor = require("./editor").Editor; |
||
898 | (function() { |
||
899 | this.insertSnippet = function(content, options) { |
||
900 | return exports.snippetManager.insertSnippet(this, content, options); |
||
901 | }; |
||
902 | this.expandSnippet = function(options) { |
||
903 | return exports.snippetManager.expandWithTab(this, options); |
||
904 | }; |
||
905 | }).call(Editor.prototype); |
||
906 | |||
907 | }); |
||
908 | |||
909 | define("ace/autocomplete/popup",["require","exports","module","ace/virtual_renderer","ace/editor","ace/range","ace/lib/event","ace/lib/lang","ace/lib/dom"], function(require, exports, module) { |
||
910 | "use strict"; |
||
911 | |||
912 | var Renderer = require("../virtual_renderer").VirtualRenderer; |
||
913 | var Editor = require("../editor").Editor; |
||
914 | var Range = require("../range").Range; |
||
915 | var event = require("../lib/event"); |
||
916 | var lang = require("../lib/lang"); |
||
917 | var dom = require("../lib/dom"); |
||
918 | |||
919 | var $singleLineEditor = function(el) { |
||
920 | var renderer = new Renderer(el); |
||
921 | |||
922 | renderer.$maxLines = 4; |
||
923 | |||
924 | var editor = new Editor(renderer); |
||
925 | |||
926 | editor.setHighlightActiveLine(false); |
||
927 | editor.setShowPrintMargin(false); |
||
928 | editor.renderer.setShowGutter(false); |
||
929 | editor.renderer.setHighlightGutterLine(false); |
||
930 | |||
931 | editor.$mouseHandler.$focusWaitTimout = 0; |
||
932 | editor.$highlightTagPending = true; |
||
933 | |||
934 | return editor; |
||
935 | }; |
||
936 | |||
937 | var AcePopup = function(parentNode) { |
||
938 | var el = dom.createElement("div"); |
||
939 | var popup = new $singleLineEditor(el); |
||
940 | |||
941 | if (parentNode) |
||
942 | parentNode.appendChild(el); |
||
943 | el.style.display = "none"; |
||
944 | popup.renderer.content.style.cursor = "default"; |
||
945 | popup.renderer.setStyle("ace_autocomplete"); |
||
946 | |||
947 | popup.setOption("displayIndentGuides", false); |
||
948 | popup.setOption("dragDelay", 150); |
||
949 | |||
950 | var noop = function(){}; |
||
951 | |||
952 | popup.focus = noop; |
||
953 | popup.$isFocused = true; |
||
954 | |||
955 | popup.renderer.$cursorLayer.restartTimer = noop; |
||
956 | popup.renderer.$cursorLayer.element.style.opacity = 0; |
||
957 | |||
958 | popup.renderer.$maxLines = 8; |
||
959 | popup.renderer.$keepTextAreaAtCursor = false; |
||
960 | |||
961 | popup.setHighlightActiveLine(false); |
||
962 | popup.session.highlight(""); |
||
963 | popup.session.$searchHighlight.clazz = "ace_highlight-marker"; |
||
964 | |||
965 | popup.on("mousedown", function(e) { |
||
966 | var pos = e.getDocumentPosition(); |
||
967 | popup.selection.moveToPosition(pos); |
||
968 | selectionMarker.start.row = selectionMarker.end.row = pos.row; |
||
969 | e.stop(); |
||
970 | }); |
||
971 | |||
972 | var lastMouseEvent; |
||
973 | var hoverMarker = new Range(-1,0,-1,Infinity); |
||
974 | var selectionMarker = new Range(-1,0,-1,Infinity); |
||
975 | selectionMarker.id = popup.session.addMarker(selectionMarker, "ace_active-line", "fullLine"); |
||
976 | popup.setSelectOnHover = function(val) { |
||
977 | if (!val) { |
||
978 | hoverMarker.id = popup.session.addMarker(hoverMarker, "ace_line-hover", "fullLine"); |
||
979 | } else if (hoverMarker.id) { |
||
980 | popup.session.removeMarker(hoverMarker.id); |
||
981 | hoverMarker.id = null; |
||
982 | } |
||
983 | }; |
||
984 | popup.setSelectOnHover(false); |
||
985 | popup.on("mousemove", function(e) { |
||
986 | if (!lastMouseEvent) { |
||
987 | lastMouseEvent = e; |
||
988 | return; |
||
989 | } |
||
990 | if (lastMouseEvent.x == e.x && lastMouseEvent.y == e.y) { |
||
991 | return; |
||
992 | } |
||
993 | lastMouseEvent = e; |
||
994 | lastMouseEvent.scrollTop = popup.renderer.scrollTop; |
||
995 | var row = lastMouseEvent.getDocumentPosition().row; |
||
996 | if (hoverMarker.start.row != row) { |
||
997 | if (!hoverMarker.id) |
||
998 | popup.setRow(row); |
||
999 | setHoverMarker(row); |
||
1000 | } |
||
1001 | }); |
||
1002 | popup.renderer.on("beforeRender", function() { |
||
1003 | if (lastMouseEvent && hoverMarker.start.row != -1) { |
||
1004 | lastMouseEvent.$pos = null; |
||
1005 | var row = lastMouseEvent.getDocumentPosition().row; |
||
1006 | if (!hoverMarker.id) |
||
1007 | popup.setRow(row); |
||
1008 | setHoverMarker(row, true); |
||
1009 | } |
||
1010 | }); |
||
1011 | popup.renderer.on("afterRender", function() { |
||
1012 | var row = popup.getRow(); |
||
1013 | var t = popup.renderer.$textLayer; |
||
1014 | var selected = t.element.childNodes[row - t.config.firstRow]; |
||
1015 | if (selected == t.selectedNode) |
||
1016 | return; |
||
1017 | if (t.selectedNode) |
||
1018 | dom.removeCssClass(t.selectedNode, "ace_selected"); |
||
1019 | t.selectedNode = selected; |
||
1020 | if (selected) |
||
1021 | dom.addCssClass(selected, "ace_selected"); |
||
1022 | }); |
||
1023 | var hideHoverMarker = function() { setHoverMarker(-1) }; |
||
1024 | var setHoverMarker = function(row, suppressRedraw) { |
||
1025 | if (row !== hoverMarker.start.row) { |
||
1026 | hoverMarker.start.row = hoverMarker.end.row = row; |
||
1027 | if (!suppressRedraw) |
||
1028 | popup.session._emit("changeBackMarker"); |
||
1029 | popup._emit("changeHoverMarker"); |
||
1030 | } |
||
1031 | }; |
||
1032 | popup.getHoveredRow = function() { |
||
1033 | return hoverMarker.start.row; |
||
1034 | }; |
||
1035 | |||
1036 | event.addListener(popup.container, "mouseout", hideHoverMarker); |
||
1037 | popup.on("hide", hideHoverMarker); |
||
1038 | popup.on("changeSelection", hideHoverMarker); |
||
1039 | |||
1040 | popup.session.doc.getLength = function() { |
||
1041 | return popup.data.length; |
||
1042 | }; |
||
1043 | popup.session.doc.getLine = function(i) { |
||
1044 | var data = popup.data[i]; |
||
1045 | if (typeof data == "string") |
||
1046 | return data; |
||
1047 | return (data && data.value) || ""; |
||
1048 | }; |
||
1049 | |||
1050 | var bgTokenizer = popup.session.bgTokenizer; |
||
1051 | bgTokenizer.$tokenizeRow = function(row) { |
||
1052 | var data = popup.data[row]; |
||
1053 | var tokens = []; |
||
1054 | if (!data) |
||
1055 | return tokens; |
||
1056 | if (typeof data == "string") |
||
1057 | data = {value: data}; |
||
1058 | if (!data.caption) |
||
1059 | data.caption = data.value || data.name; |
||
1060 | |||
1061 | var last = -1; |
||
1062 | var flag, c; |
||
1063 | for (var i = 0; i < data.caption.length; i++) { |
||
1064 | c = data.caption[i]; |
||
1065 | flag = data.matchMask & (1 << i) ? 1 : 0; |
||
1066 | if (last !== flag) { |
||
1067 | tokens.push({type: data.className || "" + ( flag ? "completion-highlight" : ""), value: c}); |
||
1068 | last = flag; |
||
1069 | } else { |
||
1070 | tokens[tokens.length - 1].value += c; |
||
1071 | } |
||
1072 | } |
||
1073 | |||
1074 | if (data.meta) { |
||
1075 | var maxW = popup.renderer.$size.scrollerWidth / popup.renderer.layerConfig.characterWidth; |
||
1076 | var metaData = data.meta; |
||
1077 | if (metaData.length + data.caption.length > maxW - 2) { |
||
1078 | metaData = metaData.substr(0, maxW - data.caption.length - 3) + "\u2026" |
||
1079 | } |
||
1080 | tokens.push({type: "rightAlignedText", value: metaData}); |
||
1081 | } |
||
1082 | return tokens; |
||
1083 | }; |
||
1084 | bgTokenizer.$updateOnChange = noop; |
||
1085 | bgTokenizer.start = noop; |
||
1086 | |||
1087 | popup.session.$computeWidth = function() { |
||
1088 | return this.screenWidth = 0; |
||
1089 | }; |
||
1090 | |||
1091 | popup.$blockScrolling = Infinity; |
||
1092 | popup.isOpen = false; |
||
1093 | popup.isTopdown = false; |
||
1094 | |||
1095 | popup.data = []; |
||
1096 | popup.setData = function(list) { |
||
1097 | popup.setValue(lang.stringRepeat("\n", list.length), -1); |
||
1098 | popup.data = list || []; |
||
1099 | popup.setRow(0); |
||
1100 | }; |
||
1101 | popup.getData = function(row) { |
||
1102 | return popup.data[row]; |
||
1103 | }; |
||
1104 | |||
1105 | popup.getRow = function() { |
||
1106 | return selectionMarker.start.row; |
||
1107 | }; |
||
1108 | popup.setRow = function(line) { |
||
1109 | line = Math.max(0, Math.min(this.data.length, line)); |
||
1110 | if (selectionMarker.start.row != line) { |
||
1111 | popup.selection.clearSelection(); |
||
1112 | selectionMarker.start.row = selectionMarker.end.row = line || 0; |
||
1113 | popup.session._emit("changeBackMarker"); |
||
1114 | popup.moveCursorTo(line || 0, 0); |
||
1115 | if (popup.isOpen) |
||
1116 | popup._signal("select"); |
||
1117 | } |
||
1118 | }; |
||
1119 | |||
1120 | popup.on("changeSelection", function() { |
||
1121 | if (popup.isOpen) |
||
1122 | popup.setRow(popup.selection.lead.row); |
||
1123 | popup.renderer.scrollCursorIntoView(); |
||
1124 | }); |
||
1125 | |||
1126 | popup.hide = function() { |
||
1127 | this.container.style.display = "none"; |
||
1128 | this._signal("hide"); |
||
1129 | popup.isOpen = false; |
||
1130 | }; |
||
1131 | popup.show = function(pos, lineHeight, topdownOnly) { |
||
1132 | var el = this.container; |
||
1133 | var screenHeight = window.innerHeight; |
||
1134 | var screenWidth = window.innerWidth; |
||
1135 | var renderer = this.renderer; |
||
1136 | var maxH = renderer.$maxLines * lineHeight * 1.4; |
||
1137 | var top = pos.top + this.$borderSize; |
||
1138 | var allowTopdown = top > screenHeight / 2 && !topdownOnly; |
||
1139 | if (allowTopdown && top + lineHeight + maxH > screenHeight) { |
||
1140 | renderer.$maxPixelHeight = top - 2 * this.$borderSize; |
||
1141 | el.style.top = ""; |
||
1142 | el.style.bottom = screenHeight - top + "px"; |
||
1143 | popup.isTopdown = false; |
||
1144 | } else { |
||
1145 | top += lineHeight; |
||
1146 | renderer.$maxPixelHeight = screenHeight - top - 0.2 * lineHeight; |
||
1147 | el.style.top = top + "px"; |
||
1148 | el.style.bottom = ""; |
||
1149 | popup.isTopdown = true; |
||
1150 | } |
||
1151 | |||
1152 | el.style.display = ""; |
||
1153 | this.renderer.$textLayer.checkForSizeChanges(); |
||
1154 | |||
1155 | var left = pos.left; |
||
1156 | if (left + el.offsetWidth > screenWidth) |
||
1157 | left = screenWidth - el.offsetWidth; |
||
1158 | |||
1159 | el.style.left = left + "px"; |
||
1160 | |||
1161 | this._signal("show"); |
||
1162 | lastMouseEvent = null; |
||
1163 | popup.isOpen = true; |
||
1164 | }; |
||
1165 | |||
1166 | popup.getTextLeftOffset = function() { |
||
1167 | return this.$borderSize + this.renderer.$padding + this.$imageSize; |
||
1168 | }; |
||
1169 | |||
1170 | popup.$imageSize = 0; |
||
1171 | popup.$borderSize = 1; |
||
1172 | |||
1173 | return popup; |
||
1174 | }; |
||
1175 | |||
1176 | dom.importCssString("\ |
||
1177 | .ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {\ |
||
1178 | background-color: #CAD6FA;\ |
||
1179 | z-index: 1;\ |
||
1180 | }\ |
||
1181 | .ace_editor.ace_autocomplete .ace_line-hover {\ |
||
1182 | border: 1px solid #abbffe;\ |
||
1183 | margin-top: -1px;\ |
||
1184 | background: rgba(233,233,253,0.4);\ |
||
1185 | }\ |
||
1186 | .ace_editor.ace_autocomplete .ace_line-hover {\ |
||
1187 | position: absolute;\ |
||
1188 | z-index: 2;\ |
||
1189 | }\ |
||
1190 | .ace_editor.ace_autocomplete .ace_scroller {\ |
||
1191 | background: none;\ |
||
1192 | border: none;\ |
||
1193 | box-shadow: none;\ |
||
1194 | }\ |
||
1195 | .ace_rightAlignedText {\ |
||
1196 | color: gray;\ |
||
1197 | display: inline-block;\ |
||
1198 | position: absolute;\ |
||
1199 | right: 4px;\ |
||
1200 | text-align: right;\ |
||
1201 | z-index: -1;\ |
||
1202 | }\ |
||
1203 | .ace_editor.ace_autocomplete .ace_completion-highlight{\ |
||
1204 | color: #000;\ |
||
1205 | text-shadow: 0 0 0.01em;\ |
||
1206 | }\ |
||
1207 | .ace_editor.ace_autocomplete {\ |
||
1208 | width: 280px;\ |
||
1209 | z-index: 200000;\ |
||
1210 | background: #fbfbfb;\ |
||
1211 | color: #444;\ |
||
1212 | border: 1px lightgray solid;\ |
||
1213 | position: fixed;\ |
||
1214 | box-shadow: 2px 3px 5px rgba(0,0,0,.2);\ |
||
1215 | line-height: 1.4;\ |
||
1216 | }"); |
||
1217 | |||
1218 | exports.AcePopup = AcePopup; |
||
1219 | |||
1220 | }); |
||
1221 | |||
1222 | define("ace/autocomplete/util",["require","exports","module"], function(require, exports, module) { |
||
1223 | "use strict"; |
||
1224 | |||
1225 | exports.parForEach = function(array, fn, callback) { |
||
1226 | var completed = 0; |
||
1227 | var arLength = array.length; |
||
1228 | if (arLength === 0) |
||
1229 | callback(); |
||
1230 | for (var i = 0; i < arLength; i++) { |
||
1231 | fn(array[i], function(result, err) { |
||
1232 | completed++; |
||
1233 | if (completed === arLength) |
||
1234 | callback(result, err); |
||
1235 | }); |
||
1236 | } |
||
1237 | }; |
||
1238 | |||
1239 | var ID_REGEX = /[a-zA-Z_0-9\$\-\u00A2-\uFFFF]/; |
||
1240 | |||
1241 | exports.retrievePrecedingIdentifier = function(text, pos, regex) { |
||
1242 | regex = regex || ID_REGEX; |
||
1243 | var buf = []; |
||
1244 | for (var i = pos-1; i >= 0; i--) { |
||
1245 | if (regex.test(text[i])) |
||
1246 | buf.push(text[i]); |
||
1247 | else |
||
1248 | break; |
||
1249 | } |
||
1250 | return buf.reverse().join(""); |
||
1251 | }; |
||
1252 | |||
1253 | exports.retrieveFollowingIdentifier = function(text, pos, regex) { |
||
1254 | regex = regex || ID_REGEX; |
||
1255 | var buf = []; |
||
1256 | for (var i = pos; i < text.length; i++) { |
||
1257 | if (regex.test(text[i])) |
||
1258 | buf.push(text[i]); |
||
1259 | else |
||
1260 | break; |
||
1261 | } |
||
1262 | return buf; |
||
1263 | }; |
||
1264 | |||
1265 | exports.getCompletionPrefix = function (editor) { |
||
1266 | var pos = editor.getCursorPosition(); |
||
1267 | var line = editor.session.getLine(pos.row); |
||
1268 | var prefix; |
||
1269 | editor.completers.forEach(function(completer) { |
||
1270 | if (completer.identifierRegexps) { |
||
1271 | completer.identifierRegexps.forEach(function(identifierRegex) { |
||
1272 | if (!prefix && identifierRegex) |
||
1273 | prefix = this.retrievePrecedingIdentifier(line, pos.column, identifierRegex); |
||
1274 | }.bind(this)); |
||
1275 | } |
||
1276 | }.bind(this)); |
||
1277 | return prefix || this.retrievePrecedingIdentifier(line, pos.column); |
||
1278 | }; |
||
1279 | |||
1280 | }); |
||
1281 | |||
1282 | define("ace/autocomplete",["require","exports","module","ace/keyboard/hash_handler","ace/autocomplete/popup","ace/autocomplete/util","ace/lib/event","ace/lib/lang","ace/lib/dom","ace/snippets"], function(require, exports, module) { |
||
1283 | "use strict"; |
||
1284 | |||
1285 | var HashHandler = require("./keyboard/hash_handler").HashHandler; |
||
1286 | var AcePopup = require("./autocomplete/popup").AcePopup; |
||
1287 | var util = require("./autocomplete/util"); |
||
1288 | var event = require("./lib/event"); |
||
1289 | var lang = require("./lib/lang"); |
||
1290 | var dom = require("./lib/dom"); |
||
1291 | var snippetManager = require("./snippets").snippetManager; |
||
1292 | |||
1293 | var Autocomplete = function() { |
||
1294 | this.autoInsert = false; |
||
1295 | this.autoSelect = true; |
||
1296 | this.exactMatch = false; |
||
1297 | this.gatherCompletionsId = 0; |
||
1298 | this.keyboardHandler = new HashHandler(); |
||
1299 | this.keyboardHandler.bindKeys(this.commands); |
||
1300 | |||
1301 | this.blurListener = this.blurListener.bind(this); |
||
1302 | this.changeListener = this.changeListener.bind(this); |
||
1303 | this.mousedownListener = this.mousedownListener.bind(this); |
||
1304 | this.mousewheelListener = this.mousewheelListener.bind(this); |
||
1305 | |||
1306 | this.changeTimer = lang.delayedCall(function() { |
||
1307 | this.updateCompletions(true); |
||
1308 | }.bind(this)); |
||
1309 | |||
1310 | this.tooltipTimer = lang.delayedCall(this.updateDocTooltip.bind(this), 50); |
||
1311 | }; |
||
1312 | |||
1313 | (function() { |
||
1314 | |||
1315 | this.$init = function() { |
||
1316 | this.popup = new AcePopup(document.body || document.documentElement); |
||
1317 | this.popup.on("click", function(e) { |
||
1318 | this.insertMatch(); |
||
1319 | e.stop(); |
||
1320 | }.bind(this)); |
||
1321 | this.popup.focus = this.editor.focus.bind(this.editor); |
||
1322 | this.popup.on("show", this.tooltipTimer.bind(null, null)); |
||
1323 | this.popup.on("select", this.tooltipTimer.bind(null, null)); |
||
1324 | this.popup.on("changeHoverMarker", this.tooltipTimer.bind(null, null)); |
||
1325 | return this.popup; |
||
1326 | }; |
||
1327 | |||
1328 | this.getPopup = function() { |
||
1329 | return this.popup || this.$init(); |
||
1330 | }; |
||
1331 | |||
1332 | this.openPopup = function(editor, prefix, keepPopupPosition) { |
||
1333 | if (!this.popup) |
||
1334 | this.$init(); |
||
1335 | |||
1336 | this.popup.setData(this.completions.filtered); |
||
1337 | |||
1338 | editor.keyBinding.addKeyboardHandler(this.keyboardHandler); |
||
1339 | |||
1340 | var renderer = editor.renderer; |
||
1341 | this.popup.setRow(this.autoSelect ? 0 : -1); |
||
1342 | if (!keepPopupPosition) { |
||
1343 | this.popup.setTheme(editor.getTheme()); |
||
1344 | this.popup.setFontSize(editor.getFontSize()); |
||
1345 | |||
1346 | var lineHeight = renderer.layerConfig.lineHeight; |
||
1347 | |||
1348 | var pos = renderer.$cursorLayer.getPixelPosition(this.base, true); |
||
1349 | pos.left -= this.popup.getTextLeftOffset(); |
||
1350 | |||
1351 | var rect = editor.container.getBoundingClientRect(); |
||
1352 | pos.top += rect.top - renderer.layerConfig.offset; |
||
1353 | pos.left += rect.left - editor.renderer.scrollLeft; |
||
1354 | pos.left += renderer.gutterWidth; |
||
1355 | |||
1356 | this.popup.show(pos, lineHeight); |
||
1357 | } else if (keepPopupPosition && !prefix) { |
||
1358 | this.detach(); |
||
1359 | } |
||
1360 | }; |
||
1361 | |||
1362 | this.detach = function() { |
||
1363 | this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler); |
||
1364 | this.editor.off("changeSelection", this.changeListener); |
||
1365 | this.editor.off("blur", this.blurListener); |
||
1366 | this.editor.off("mousedown", this.mousedownListener); |
||
1367 | this.editor.off("mousewheel", this.mousewheelListener); |
||
1368 | this.changeTimer.cancel(); |
||
1369 | this.hideDocTooltip(); |
||
1370 | |||
1371 | this.gatherCompletionsId += 1; |
||
1372 | if (this.popup && this.popup.isOpen) |
||
1373 | this.popup.hide(); |
||
1374 | |||
1375 | if (this.base) |
||
1376 | this.base.detach(); |
||
1377 | this.activated = false; |
||
1378 | this.completions = this.base = null; |
||
1379 | }; |
||
1380 | |||
1381 | this.changeListener = function(e) { |
||
1382 | var cursor = this.editor.selection.lead; |
||
1383 | if (cursor.row != this.base.row || cursor.column < this.base.column) { |
||
1384 | this.detach(); |
||
1385 | } |
||
1386 | if (this.activated) |
||
1387 | this.changeTimer.schedule(); |
||
1388 | else |
||
1389 | this.detach(); |
||
1390 | }; |
||
1391 | |||
1392 | this.blurListener = function(e) { |
||
1393 | if (e.relatedTarget && e.relatedTarget.nodeName == "A" && e.relatedTarget.href) { |
||
1394 | window.open(e.relatedTarget.href, "_blank"); |
||
1395 | } |
||
1396 | var el = document.activeElement; |
||
1397 | var text = this.editor.textInput.getElement(); |
||
1398 | var fromTooltip = e.relatedTarget && e.relatedTarget == this.tooltipNode; |
||
1399 | var container = this.popup && this.popup.container; |
||
1400 | if (el != text && el.parentNode != container && !fromTooltip |
||
1401 | && el != this.tooltipNode && e.relatedTarget != text |
||
1402 | ) { |
||
1403 | this.detach(); |
||
1404 | } |
||
1405 | }; |
||
1406 | |||
1407 | this.mousedownListener = function(e) { |
||
1408 | this.detach(); |
||
1409 | }; |
||
1410 | |||
1411 | this.mousewheelListener = function(e) { |
||
1412 | this.detach(); |
||
1413 | }; |
||
1414 | |||
1415 | this.goTo = function(where) { |
||
1416 | var row = this.popup.getRow(); |
||
1417 | var max = this.popup.session.getLength() - 1; |
||
1418 | |||
1419 | switch(where) { |
||
1420 | case "up": row = row <= 0 ? max : row - 1; break; |
||
1421 | case "down": row = row >= max ? -1 : row + 1; break; |
||
1422 | case "start": row = 0; break; |
||
1423 | case "end": row = max; break; |
||
1424 | } |
||
1425 | |||
1426 | this.popup.setRow(row); |
||
1427 | }; |
||
1428 | |||
1429 | this.insertMatch = function(data, options) { |
||
1430 | if (!data) |
||
1431 | data = this.popup.getData(this.popup.getRow()); |
||
1432 | if (!data) |
||
1433 | return false; |
||
1434 | |||
1435 | if (data.completer && data.completer.insertMatch) { |
||
1436 | data.completer.insertMatch(this.editor, data); |
||
1437 | } else { |
||
1438 | if (this.completions.filterText) { |
||
1439 | var ranges = this.editor.selection.getAllRanges(); |
||
1440 | for (var i = 0, range; range = ranges[i]; i++) { |
||
1441 | range.start.column -= this.completions.filterText.length; |
||
1442 | this.editor.session.remove(range); |
||
1443 | } |
||
1444 | } |
||
1445 | if (data.snippet) |
||
1446 | snippetManager.insertSnippet(this.editor, data.snippet); |
||
1447 | else |
||
1448 | this.editor.execCommand("insertstring", data.value || data); |
||
1449 | } |
||
1450 | this.detach(); |
||
1451 | }; |
||
1452 | |||
1453 | |||
1454 | this.commands = { |
||
1455 | "Up": function(editor) { editor.completer.goTo("up"); }, |
||
1456 | "Down": function(editor) { editor.completer.goTo("down"); }, |
||
1457 | "Ctrl-Up|Ctrl-Home": function(editor) { editor.completer.goTo("start"); }, |
||
1458 | "Ctrl-Down|Ctrl-End": function(editor) { editor.completer.goTo("end"); }, |
||
1459 | |||
1460 | "Esc": function(editor) { editor.completer.detach(); }, |
||
1461 | "Return": function(editor) { return editor.completer.insertMatch(); }, |
||
1462 | "Shift-Return": function(editor) { editor.completer.insertMatch(null, {deleteSuffix: true}); }, |
||
1463 | "Tab": function(editor) { |
||
1464 | var result = editor.completer.insertMatch(); |
||
1465 | if (!result && !editor.tabstopManager) |
||
1466 | editor.completer.goTo("down"); |
||
1467 | else |
||
1468 | return result; |
||
1469 | }, |
||
1470 | |||
1471 | "PageUp": function(editor) { editor.completer.popup.gotoPageUp(); }, |
||
1472 | "PageDown": function(editor) { editor.completer.popup.gotoPageDown(); } |
||
1473 | }; |
||
1474 | |||
1475 | this.gatherCompletions = function(editor, callback) { |
||
1476 | var session = editor.getSession(); |
||
1477 | var pos = editor.getCursorPosition(); |
||
1478 | |||
1479 | var line = session.getLine(pos.row); |
||
1480 | var prefix = util.getCompletionPrefix(editor); |
||
1481 | |||
1482 | this.base = session.doc.createAnchor(pos.row, pos.column - prefix.length); |
||
1483 | this.base.$insertRight = true; |
||
1484 | |||
1485 | var matches = []; |
||
1486 | var total = editor.completers.length; |
||
1487 | editor.completers.forEach(function(completer, i) { |
||
1488 | completer.getCompletions(editor, session, pos, prefix, function(err, results) { |
||
1489 | if (!err && results) |
||
1490 | matches = matches.concat(results); |
||
1491 | var pos = editor.getCursorPosition(); |
||
1492 | var line = session.getLine(pos.row); |
||
1493 | callback(null, { |
||
1494 | prefix: prefix, |
||
1495 | matches: matches, |
||
1496 | finished: (--total === 0) |
||
1497 | }); |
||
1498 | }); |
||
1499 | }); |
||
1500 | return true; |
||
1501 | }; |
||
1502 | |||
1503 | this.showPopup = function(editor) { |
||
1504 | if (this.editor) |
||
1505 | this.detach(); |
||
1506 | |||
1507 | this.activated = true; |
||
1508 | |||
1509 | this.editor = editor; |
||
1510 | if (editor.completer != this) { |
||
1511 | if (editor.completer) |
||
1512 | editor.completer.detach(); |
||
1513 | editor.completer = this; |
||
1514 | } |
||
1515 | |||
1516 | editor.on("changeSelection", this.changeListener); |
||
1517 | editor.on("blur", this.blurListener); |
||
1518 | editor.on("mousedown", this.mousedownListener); |
||
1519 | editor.on("mousewheel", this.mousewheelListener); |
||
1520 | |||
1521 | this.updateCompletions(); |
||
1522 | }; |
||
1523 | |||
1524 | this.updateCompletions = function(keepPopupPosition) { |
||
1525 | if (keepPopupPosition && this.base && this.completions) { |
||
1526 | var pos = this.editor.getCursorPosition(); |
||
1527 | var prefix = this.editor.session.getTextRange({start: this.base, end: pos}); |
||
1528 | if (prefix == this.completions.filterText) |
||
1529 | return; |
||
1530 | this.completions.setFilter(prefix); |
||
1531 | if (!this.completions.filtered.length) |
||
1532 | return this.detach(); |
||
1533 | if (this.completions.filtered.length == 1 |
||
1534 | && this.completions.filtered[0].value == prefix |
||
1535 | && !this.completions.filtered[0].snippet) |
||
1536 | return this.detach(); |
||
1537 | this.openPopup(this.editor, prefix, keepPopupPosition); |
||
1538 | return; |
||
1539 | } |
||
1540 | var _id = this.gatherCompletionsId; |
||
1541 | this.gatherCompletions(this.editor, function(err, results) { |
||
1542 | var detachIfFinished = function() { |
||
1543 | if (!results.finished) return; |
||
1544 | return this.detach(); |
||
1545 | }.bind(this); |
||
1546 | |||
1547 | var prefix = results.prefix; |
||
1548 | var matches = results && results.matches; |
||
1549 | |||
1550 | if (!matches || !matches.length) |
||
1551 | return detachIfFinished(); |
||
1552 | if (prefix.indexOf(results.prefix) !== 0 || _id != this.gatherCompletionsId) |
||
1553 | return; |
||
1554 | |||
1555 | this.completions = new FilteredList(matches); |
||
1556 | |||
1557 | if (this.exactMatch) |
||
1558 | this.completions.exactMatch = true; |
||
1559 | |||
1560 | this.completions.setFilter(prefix); |
||
1561 | var filtered = this.completions.filtered; |
||
1562 | if (!filtered.length) |
||
1563 | return detachIfFinished(); |
||
1564 | if (filtered.length == 1 && filtered[0].value == prefix && !filtered[0].snippet) |
||
1565 | return detachIfFinished(); |
||
1566 | if (this.autoInsert && filtered.length == 1 && results.finished) |
||
1567 | return this.insertMatch(filtered[0]); |
||
1568 | |||
1569 | this.openPopup(this.editor, prefix, keepPopupPosition); |
||
1570 | }.bind(this)); |
||
1571 | }; |
||
1572 | |||
1573 | this.cancelContextMenu = function() { |
||
1574 | this.editor.$mouseHandler.cancelContextMenu(); |
||
1575 | }; |
||
1576 | |||
1577 | this.updateDocTooltip = function() { |
||
1578 | var popup = this.popup; |
||
1579 | var all = popup.data; |
||
1580 | var selected = all && (all[popup.getHoveredRow()] || all[popup.getRow()]); |
||
1581 | var doc = null; |
||
1582 | if (!selected || !this.editor || !this.popup.isOpen) |
||
1583 | return this.hideDocTooltip(); |
||
1584 | this.editor.completers.some(function(completer) { |
||
1585 | if (completer.getDocTooltip) |
||
1586 | doc = completer.getDocTooltip(selected); |
||
1587 | return doc; |
||
1588 | }); |
||
1589 | if (!doc) |
||
1590 | doc = selected; |
||
1591 | |||
1592 | if (typeof doc == "string") |
||
1593 | doc = {docText: doc}; |
||
1594 | if (!doc || !(doc.docHTML || doc.docText)) |
||
1595 | return this.hideDocTooltip(); |
||
1596 | this.showDocTooltip(doc); |
||
1597 | }; |
||
1598 | |||
1599 | this.showDocTooltip = function(item) { |
||
1600 | if (!this.tooltipNode) { |
||
1601 | this.tooltipNode = dom.createElement("div"); |
||
1602 | this.tooltipNode.className = "ace_tooltip ace_doc-tooltip"; |
||
1603 | this.tooltipNode.style.margin = 0; |
||
1604 | this.tooltipNode.style.pointerEvents = "auto"; |
||
1605 | this.tooltipNode.tabIndex = -1; |
||
1606 | this.tooltipNode.onblur = this.blurListener.bind(this); |
||
1607 | } |
||
1608 | |||
1609 | var tooltipNode = this.tooltipNode; |
||
1610 | if (item.docHTML) { |
||
1611 | tooltipNode.innerHTML = item.docHTML; |
||
1612 | } else if (item.docText) { |
||
1613 | tooltipNode.textContent = item.docText; |
||
1614 | } |
||
1615 | |||
1616 | if (!tooltipNode.parentNode) |
||
1617 | document.body.appendChild(tooltipNode); |
||
1618 | var popup = this.popup; |
||
1619 | var rect = popup.container.getBoundingClientRect(); |
||
1620 | tooltipNode.style.top = popup.container.style.top; |
||
1621 | tooltipNode.style.bottom = popup.container.style.bottom; |
||
1622 | |||
1623 | if (window.innerWidth - rect.right < 320) { |
||
1624 | tooltipNode.style.right = window.innerWidth - rect.left + "px"; |
||
1625 | tooltipNode.style.left = ""; |
||
1626 | } else { |
||
1627 | tooltipNode.style.left = (rect.right + 1) + "px"; |
||
1628 | tooltipNode.style.right = ""; |
||
1629 | } |
||
1630 | tooltipNode.style.display = "block"; |
||
1631 | }; |
||
1632 | |||
1633 | this.hideDocTooltip = function() { |
||
1634 | this.tooltipTimer.cancel(); |
||
1635 | if (!this.tooltipNode) return; |
||
1636 | var el = this.tooltipNode; |
||
1637 | if (!this.editor.isFocused() && document.activeElement == el) |
||
1638 | this.editor.focus(); |
||
1639 | this.tooltipNode = null; |
||
1640 | if (el.parentNode) |
||
1641 | el.parentNode.removeChild(el); |
||
1642 | }; |
||
1643 | |||
1644 | }).call(Autocomplete.prototype); |
||
1645 | |||
1646 | Autocomplete.startCommand = { |
||
1647 | name: "startAutocomplete", |
||
1648 | exec: function(editor) { |
||
1649 | if (!editor.completer) |
||
1650 | editor.completer = new Autocomplete(); |
||
1651 | editor.completer.autoInsert = false; |
||
1652 | editor.completer.autoSelect = true; |
||
1653 | editor.completer.showPopup(editor); |
||
1654 | editor.completer.cancelContextMenu(); |
||
1655 | }, |
||
1656 | bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space" |
||
1657 | }; |
||
1658 | |||
1659 | var FilteredList = function(array, filterText) { |
||
1660 | this.all = array; |
||
1661 | this.filtered = array; |
||
1662 | this.filterText = filterText || ""; |
||
1663 | this.exactMatch = false; |
||
1664 | }; |
||
1665 | (function(){ |
||
1666 | this.setFilter = function(str) { |
||
1667 | if (str.length > this.filterText && str.lastIndexOf(this.filterText, 0) === 0) |
||
1668 | var matches = this.filtered; |
||
1669 | else |
||
1670 | var matches = this.all; |
||
1671 | |||
1672 | this.filterText = str; |
||
1673 | matches = this.filterCompletions(matches, this.filterText); |
||
1674 | matches = matches.sort(function(a, b) { |
||
1675 | return b.exactMatch - a.exactMatch || b.score - a.score; |
||
1676 | }); |
||
1677 | var prev = null; |
||
1678 | matches = matches.filter(function(item){ |
||
1679 | var caption = item.snippet || item.caption || item.value; |
||
1680 | if (caption === prev) return false; |
||
1681 | prev = caption; |
||
1682 | return true; |
||
1683 | }); |
||
1684 | |||
1685 | this.filtered = matches; |
||
1686 | }; |
||
1687 | this.filterCompletions = function(items, needle) { |
||
1688 | var results = []; |
||
1689 | var upper = needle.toUpperCase(); |
||
1690 | var lower = needle.toLowerCase(); |
||
1691 | loop: for (var i = 0, item; item = items[i]; i++) { |
||
1692 | var caption = item.value || item.caption || item.snippet; |
||
1693 | if (!caption) continue; |
||
1694 | var lastIndex = -1; |
||
1695 | var matchMask = 0; |
||
1696 | var penalty = 0; |
||
1697 | var index, distance; |
||
1698 | |||
1699 | if (this.exactMatch) { |
||
1700 | if (needle !== caption.substr(0, needle.length)) |
||
1701 | continue loop; |
||
1702 | }else{ |
||
1703 | for (var j = 0; j < needle.length; j++) { |
||
1704 | var i1 = caption.indexOf(lower[j], lastIndex + 1); |
||
1705 | var i2 = caption.indexOf(upper[j], lastIndex + 1); |
||
1706 | index = (i1 >= 0) ? ((i2 < 0 || i1 < i2) ? i1 : i2) : i2; |
||
1707 | if (index < 0) |
||
1708 | continue loop; |
||
1709 | distance = index - lastIndex - 1; |
||
1710 | if (distance > 0) { |
||
1711 | if (lastIndex === -1) |
||
1712 | penalty += 10; |
||
1713 | penalty += distance; |
||
1714 | } |
||
1715 | matchMask = matchMask | (1 << index); |
||
1716 | lastIndex = index; |
||
1717 | } |
||
1718 | } |
||
1719 | item.matchMask = matchMask; |
||
1720 | item.exactMatch = penalty ? 0 : 1; |
||
1721 | item.score = (item.score || 0) - penalty; |
||
1722 | results.push(item); |
||
1723 | } |
||
1724 | return results; |
||
1725 | }; |
||
1726 | }).call(FilteredList.prototype); |
||
1727 | |||
1728 | exports.Autocomplete = Autocomplete; |
||
1729 | exports.FilteredList = FilteredList; |
||
1730 | |||
1731 | }); |
||
1732 | |||
1733 | define("ace/autocomplete/text_completer",["require","exports","module","ace/range"], function(require, exports, module) { |
||
1734 | var Range = require("../range").Range; |
||
1735 | |||
1736 | var splitRegex = /[^a-zA-Z_0-9\$\-\u00C0-\u1FFF\u2C00-\uD7FF\w]+/; |
||
1737 | |||
1738 | function getWordIndex(doc, pos) { |
||
1739 | var textBefore = doc.getTextRange(Range.fromPoints({row: 0, column:0}, pos)); |
||
1740 | return textBefore.split(splitRegex).length - 1; |
||
1741 | } |
||
1742 | function wordDistance(doc, pos) { |
||
1743 | var prefixPos = getWordIndex(doc, pos); |
||
1744 | var words = doc.getValue().split(splitRegex); |
||
1745 | var wordScores = Object.create(null); |
||
1746 | |||
1747 | var currentWord = words[prefixPos]; |
||
1748 | |||
1749 | words.forEach(function(word, idx) { |
||
1750 | if (!word || word === currentWord) return; |
||
1751 | |||
1752 | var distance = Math.abs(prefixPos - idx); |
||
1753 | var score = words.length - distance; |
||
1754 | if (wordScores[word]) { |
||
1755 | wordScores[word] = Math.max(score, wordScores[word]); |
||
1756 | } else { |
||
1757 | wordScores[word] = score; |
||
1758 | } |
||
1759 | }); |
||
1760 | return wordScores; |
||
1761 | } |
||
1762 | |||
1763 | exports.getCompletions = function(editor, session, pos, prefix, callback) { |
||
1764 | var wordScore = wordDistance(session, pos, prefix); |
||
1765 | var wordList = Object.keys(wordScore); |
||
1766 | callback(null, wordList.map(function(word) { |
||
1767 | return { |
||
1768 | caption: word, |
||
1769 | value: word, |
||
1770 | score: wordScore[word], |
||
1771 | meta: "local" |
||
1772 | }; |
||
1773 | })); |
||
1774 | }; |
||
1775 | }); |
||
1776 | |||
1777 | define("ace/ext/language_tools",["require","exports","module","ace/snippets","ace/autocomplete","ace/config","ace/lib/lang","ace/autocomplete/util","ace/autocomplete/text_completer","ace/editor","ace/config"], function(require, exports, module) { |
||
1778 | "use strict"; |
||
1779 | |||
1780 | var snippetManager = require("../snippets").snippetManager; |
||
1781 | var Autocomplete = require("../autocomplete").Autocomplete; |
||
1782 | var config = require("../config"); |
||
1783 | var lang = require("../lib/lang"); |
||
1784 | var util = require("../autocomplete/util"); |
||
1785 | |||
1786 | var textCompleter = require("../autocomplete/text_completer"); |
||
1787 | var keyWordCompleter = { |
||
1788 | getCompletions: function(editor, session, pos, prefix, callback) { |
||
1789 | if (session.$mode.completer) { |
||
1790 | return session.$mode.completer.getCompletions(editor, session, pos, prefix, callback); |
||
1791 | } |
||
1792 | var state = editor.session.getState(pos.row); |
||
1793 | var completions = session.$mode.getCompletions(state, session, pos, prefix); |
||
1794 | callback(null, completions); |
||
1795 | } |
||
1796 | }; |
||
1797 | |||
1798 | var snippetCompleter = { |
||
1799 | getCompletions: function(editor, session, pos, prefix, callback) { |
||
1800 | var snippetMap = snippetManager.snippetMap; |
||
1801 | var completions = []; |
||
1802 | snippetManager.getActiveScopes(editor).forEach(function(scope) { |
||
1803 | var snippets = snippetMap[scope] || []; |
||
1804 | for (var i = snippets.length; i--;) { |
||
1805 | var s = snippets[i]; |
||
1806 | var caption = s.name || s.tabTrigger; |
||
1807 | if (!caption) |
||
1808 | continue; |
||
1809 | completions.push({ |
||
1810 | caption: caption, |
||
1811 | snippet: s.content, |
||
1812 | meta: s.tabTrigger && !s.name ? s.tabTrigger + "\u21E5 " : "snippet", |
||
1813 | type: "snippet" |
||
1814 | }); |
||
1815 | } |
||
1816 | }, this); |
||
1817 | callback(null, completions); |
||
1818 | }, |
||
1819 | getDocTooltip: function(item) { |
||
1820 | if (item.type == "snippet" && !item.docHTML) { |
||
1821 | item.docHTML = [ |
||
1822 | "<b>", lang.escapeHTML(item.caption), "</b>", "<hr></hr>", |
||
1823 | lang.escapeHTML(item.snippet) |
||
1824 | ].join(""); |
||
1825 | } |
||
1826 | } |
||
1827 | }; |
||
1828 | |||
1829 | var completers = [snippetCompleter, textCompleter, keyWordCompleter]; |
||
1830 | exports.setCompleters = function(val) { |
||
1831 | completers.length = 0; |
||
1832 | if (val) completers.push.apply(completers, val); |
||
1833 | }; |
||
1834 | exports.addCompleter = function(completer) { |
||
1835 | completers.push(completer); |
||
1836 | }; |
||
1837 | exports.textCompleter = textCompleter; |
||
1838 | exports.keyWordCompleter = keyWordCompleter; |
||
1839 | exports.snippetCompleter = snippetCompleter; |
||
1840 | |||
1841 | var expandSnippet = { |
||
1842 | name: "expandSnippet", |
||
1843 | exec: function(editor) { |
||
1844 | return snippetManager.expandWithTab(editor); |
||
1845 | }, |
||
1846 | bindKey: "Tab" |
||
1847 | }; |
||
1848 | |||
1849 | var onChangeMode = function(e, editor) { |
||
1850 | loadSnippetsForMode(editor.session.$mode); |
||
1851 | }; |
||
1852 | |||
1853 | var loadSnippetsForMode = function(mode) { |
||
1854 | var id = mode.$id; |
||
1855 | if (!snippetManager.files) |
||
1856 | snippetManager.files = {}; |
||
1857 | loadSnippetFile(id); |
||
1858 | if (mode.modes) |
||
1859 | mode.modes.forEach(loadSnippetsForMode); |
||
1860 | }; |
||
1861 | |||
1862 | var loadSnippetFile = function(id) { |
||
1863 | if (!id || snippetManager.files[id]) |
||
1864 | return; |
||
1865 | var snippetFilePath = id.replace("mode", "snippets"); |
||
1866 | snippetManager.files[id] = {}; |
||
1867 | config.loadModule(snippetFilePath, function(m) { |
||
1868 | if (m) { |
||
1869 | snippetManager.files[id] = m; |
||
1870 | if (!m.snippets && m.snippetText) |
||
1871 | m.snippets = snippetManager.parseSnippetFile(m.snippetText); |
||
1872 | snippetManager.register(m.snippets || [], m.scope); |
||
1873 | if (m.includeScopes) { |
||
1874 | snippetManager.snippetMap[m.scope].includeScopes = m.includeScopes; |
||
1875 | m.includeScopes.forEach(function(x) { |
||
1876 | loadSnippetFile("ace/mode/" + x); |
||
1877 | }); |
||
1878 | } |
||
1879 | } |
||
1880 | }); |
||
1881 | }; |
||
1882 | |||
1883 | var doLiveAutocomplete = function(e) { |
||
1884 | var editor = e.editor; |
||
1885 | var hasCompleter = editor.completer && editor.completer.activated; |
||
1886 | if (e.command.name === "backspace") { |
||
1887 | if (hasCompleter && !util.getCompletionPrefix(editor)) |
||
1888 | editor.completer.detach(); |
||
1889 | } |
||
1890 | else if (e.command.name === "insertstring") { |
||
1891 | var prefix = util.getCompletionPrefix(editor); |
||
1892 | if (prefix && !hasCompleter) { |
||
1893 | if (!editor.completer) { |
||
1894 | editor.completer = new Autocomplete(); |
||
1895 | } |
||
1896 | editor.completer.autoInsert = false; |
||
1897 | editor.completer.showPopup(editor); |
||
1898 | } |
||
1899 | } |
||
1900 | }; |
||
1901 | |||
1902 | var Editor = require("../editor").Editor; |
||
1903 | require("../config").defineOptions(Editor.prototype, "editor", { |
||
1904 | enableBasicAutocompletion: { |
||
1905 | set: function(val) { |
||
1906 | if (val) { |
||
1907 | if (!this.completers) |
||
1908 | this.completers = Array.isArray(val)? val: completers; |
||
1909 | this.commands.addCommand(Autocomplete.startCommand); |
||
1910 | } else { |
||
1911 | this.commands.removeCommand(Autocomplete.startCommand); |
||
1912 | } |
||
1913 | }, |
||
1914 | value: false |
||
1915 | }, |
||
1916 | enableLiveAutocompletion: { |
||
1917 | set: function(val) { |
||
1918 | if (val) { |
||
1919 | if (!this.completers) |
||
1920 | this.completers = Array.isArray(val)? val: completers; |
||
1921 | this.commands.on('afterExec', doLiveAutocomplete); |
||
1922 | } else { |
||
1923 | this.commands.removeListener('afterExec', doLiveAutocomplete); |
||
1924 | } |
||
1925 | }, |
||
1926 | value: false |
||
1927 | }, |
||
1928 | enableSnippets: { |
||
1929 | set: function(val) { |
||
1930 | if (val) { |
||
1931 | this.commands.addCommand(expandSnippet); |
||
1932 | this.on("changeMode", onChangeMode); |
||
1933 | onChangeMode(null, this); |
||
1934 | } else { |
||
1935 | this.commands.removeCommand(expandSnippet); |
||
1936 | this.off("changeMode", onChangeMode); |
||
1937 | } |
||
1938 | }, |
||
1939 | value: false |
||
1940 | } |
||
1941 | }); |
||
1942 | }); |
||
1943 | (function() { |
||
1944 | window.require(["ace/ext/language_tools"], function() {}); |
||
1945 | })(); |
||
1946 |