| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- /* ***** BEGIN LICENSE BLOCK *****
- * Distributed under the BSD license:
- *
- * Copyright (c) 2012, Ajax.org B.V.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Ajax.org B.V. nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ***** END LICENSE BLOCK ***** */
- define(function(require, exports, module) {
- "use strict";
- var snippetManager = require("../snippets").snippetManager;
- var Autocomplete = require("../autocomplete").Autocomplete;
- var config = require("../config");
- var lang = require("../lib/lang");
- var util = require("../autocomplete/util");
- var textCompleter = require("../autocomplete/text_completer");
- var keyWordCompleter = {
- getCompletions: function(editor, session, pos, prefix, callback) {
- if (session.$mode.completer) {
- return session.$mode.completer.getCompletions(editor, session, pos, prefix, callback);
- }
- var state = editor.session.getState(pos.row);
- var completions = session.$mode.getCompletions(state, session, pos, prefix);
- callback(null, completions);
- }
- };
- var snippetCompleter = {
- getCompletions: function(editor, session, pos, prefix, callback) {
- var snippetMap = snippetManager.snippetMap;
- var completions = [];
- snippetManager.getActiveScopes(editor).forEach(function(scope) {
- var snippets = snippetMap[scope] || [];
- for (var i = snippets.length; i--;) {
- var s = snippets[i];
- var caption = s.name || s.tabTrigger;
- if (!caption)
- continue;
- completions.push({
- caption: caption,
- snippet: s.content,
- meta: s.tabTrigger && !s.name ? s.tabTrigger + "\u21E5 " : "snippet",
- type: "snippet"
- });
- }
- }, this);
- callback(null, completions);
- },
- getDocTooltip: function(item) {
- if (item.type == "snippet" && !item.docHTML) {
- item.docHTML = [
- "<b>", lang.escapeHTML(item.caption), "</b>", "<hr></hr>",
- lang.escapeHTML(item.snippet)
- ].join("");
- }
- }
- };
- var completers = [snippetCompleter, textCompleter, keyWordCompleter];
- // Allows default completers to be removed or replaced with a explict set of completers
- // A null argument here will result in an empty completer array, not a null attribute
- exports.setCompleters = function(val) {
- completers = val || [];
- };
- exports.addCompleter = function(completer) {
- completers.push(completer);
- };
- // Exports existing completer so that user can construct his own set of completers.
- exports.textCompleter = textCompleter;
- exports.keyWordCompleter = keyWordCompleter;
- exports.snippetCompleter = snippetCompleter;
- var expandSnippet = {
- name: "expandSnippet",
- exec: function(editor) {
- return snippetManager.expandWithTab(editor);
- },
- bindKey: "Tab"
- };
- var onChangeMode = function(e, editor) {
- loadSnippetsForMode(editor.session.$mode);
- };
- var loadSnippetsForMode = function(mode) {
- var id = mode.$id;
- if (!snippetManager.files)
- snippetManager.files = {};
- loadSnippetFile(id);
- if (mode.modes)
- mode.modes.forEach(loadSnippetsForMode);
- };
- var loadSnippetFile = function(id) {
- if (!id || snippetManager.files[id])
- return;
- var snippetFilePath = id.replace("mode", "snippets");
- snippetManager.files[id] = {};
- config.loadModule(snippetFilePath, function(m) {
- if (m) {
- snippetManager.files[id] = m;
- if (!m.snippets && m.snippetText)
- m.snippets = snippetManager.parseSnippetFile(m.snippetText);
- snippetManager.register(m.snippets || [], m.scope);
- if (m.includeScopes) {
- snippetManager.snippetMap[m.scope].includeScopes = m.includeScopes;
- m.includeScopes.forEach(function(x) {
- loadSnippetFile("ace/mode/" + x);
- });
- }
- }
- });
- };
- function getCompletionPrefix(editor) {
- var pos = editor.getCursorPosition();
- var line = editor.session.getLine(pos.row);
- var prefix;
- // Try to find custom prefixes on the completers
- editor.completers.forEach(function(completer) {
- if (completer.identifierRegexps) {
- completer.identifierRegexps.forEach(function(identifierRegex) {
- if (!prefix && identifierRegex)
- prefix = util.retrievePrecedingIdentifier(line, pos.column, identifierRegex);
- });
- }
- });
- return prefix || util.retrievePrecedingIdentifier(line, pos.column);
- }
- var doLiveAutocomplete = function(e) {
- var editor = e.editor;
- var prefix = getCompletionPrefix(editor);
- if (editor.useHueAutocompleter) {
- if (prefix && e.command.name === "insertstring") {
- var renderer = editor.renderer;
- var lineHeight = renderer.layerConfig.lineHeight;
- var pos = renderer.$cursorLayer.getPixelPosition(this.base, true);
- var rect = editor.container.getBoundingClientRect();
- pos.top += rect.top - renderer.layerConfig.offset;
- pos.left += rect.left - editor.renderer.scrollLeft;
- pos.left += renderer.gutterWidth;
- huePubSub.publish('hue.ace.autocompleter.show', { editor: editor, position: pos, lineHeight: lineHeight });
- } else if (e.command.name === "backspace" && !prefix) {
- huePubSub.publish('hue.ace.autocompleter.hide');
- }
- return;
- }
- var hasCompleter = editor.completer && editor.completer.activated;
- // We don't want to autocomplete with no prefix
- if (e.command.name === "backspace") {
- if (hasCompleter && !prefix)
- editor.completer.detach();
- }
- else if (e.command.name === "insertstring") {
- // Only autocomplete if there's a prefix that can be matched
- if (prefix && !hasCompleter) {
- if (!editor.completer) {
- // Create new autocompleter
- editor.completer = new Autocomplete();
- }
- // Disable autoInsert
- editor.completer.autoInsert = false;
- editor.completer.showPopup(editor);
- }
- }
- };
- var Editor = require("../editor").Editor;
- require("../config").defineOptions(Editor.prototype, "editor", {
- enableBasicAutocompletion: {
- set: function(val) {
- if (val) {
- if (!this.completers)
- this.completers = Array.isArray(val)? val: completers;
- this.commands.addCommand(Autocomplete.startCommand);
- } else {
- this.commands.removeCommand(Autocomplete.startCommand);
- }
- },
- value: false
- },
- /**
- * Enable live autocomplete. If the value is an array, it is assumed to be an array of completers
- * and will use them instead of the default completers.
- */
- enableLiveAutocompletion: {
- set: function(val) {
- if (val) {
- if (!this.completers)
- this.completers = Array.isArray(val)? val: completers;
- // On each change automatically trigger the autocomplete
- this.commands.on('afterExec', doLiveAutocomplete);
- } else {
- this.commands.removeListener('afterExec', doLiveAutocomplete);
- }
- },
- value: false
- },
- enableSnippets: {
- set: function(val) {
- if (val) {
- this.commands.addCommand(expandSnippet);
- this.on("changeMode", onChangeMode);
- onChangeMode(null, this);
- } else {
- this.commands.removeCommand(expandSnippet);
- this.off("changeMode", onChangeMode);
- }
- },
- value: false
- }
- });
- });
|