From dbca4444bfcb975c6b2f6699bd19d0469ae25f50 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Sat, 22 Dec 2012 11:26:57 -0800 Subject: [PATCH] Implement keybindings and such --- lib/ace/autocomplete.js | 121 ++++++++++++++++----------- lib/ace/commands/command_manager.js | 7 +- lib/ace/commands/default_commands.js | 5 ++ lib/ace/editor.js | 12 ++- 4 files changed, 88 insertions(+), 57 deletions(-) diff --git a/lib/ace/autocomplete.js b/lib/ace/autocomplete.js index dd53b684..25b2d73c 100644 --- a/lib/ace/autocomplete.js +++ b/lib/ace/autocomplete.js @@ -32,15 +32,17 @@ define(function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); -var EventEmitter = require("./lib/event_emitter").EventEmitter; +var Range = require('ace/range').Range; var Autocomplete = function(editor) { var self = this; - this.editor = editor; + this.$editor = editor; + + this.originalGoLineUp = editor.commands.commands.golineup.exec; + this.originalGoLineDown = editor.commands.commands.golinedown.exec; + this.originalIndent = editor.commands.commands.indent.exec; + this.originalOnTextInput = editor.onTextInput; - var originalOnTextInput = editor.onTextInput; - var originalSoftTabs = editor.session.getUseSoftTabs(); - // Create the suggest list this.autocompleteContainer = document.createElement('div'); this.autocompleteContainer.className = 'ace_autocomplete'; @@ -50,87 +52,102 @@ var Autocomplete = function(editor) { (function() { - - oop.implement(this, EventEmitter); this.current = function() { - var children = element.childNodes; + var children = this.selection.childNodes; for (var i = 0; i < children.length; i++) { var li = children[i]; - if(li.className == 'ace_autocomplete_selected') { + if (li.className == 'ace_autocomplete_selected') { return li; } }; } this.focusNext = function() { - var curr = current(); + var curr = this.current(); curr.className = ''; var focus = curr.nextSibling || curr.parentNode.firstChild; focus.className = 'ace_autocomplete_selected'; + focus.selected = true; } this.focusPrev = function() { - var curr = current(); + var curr = this.current(); curr.className = ''; var focus = curr.previousSibling || curr.parentNode.lastChild; focus.className = 'ace_autocomplete_selected'; + focus.selected = true; } this.ensureFocus = function() { - if(!current()) { - element.firstChild.className = 'ace_autocomplete_selected'; + if(!this.current()) { + this.selection.firstChild.className = 'ace_autocomplete_selected'; } } this.replace = function() { - var Range = require('ace/range').Range; - var range = new Range(self.row, self.column, self.row, self.column + 1000); - // Firefox does not support innerText property, don't know about IE - // http://blog.coderlab.us/2005/09/22/using-the-innertext-property-with-firefox/ - var selectedValue; - if(document.all){ - selectedValue = current().innerText; - } else{ - selectedValue = current().textContent; - } + var _self = this; - editor.session.replace(range, selectedValue); - // Deactivate asynchrounously, so that in case of ENTER - we don't reactivate immediately. - setTimeout(function() { - deactivate(); - }, 0); - } + var range = new Range(this.row, this.column, this.row, this.column + 1000); + + var selectedValue; + if (document.all) { + selectedValue = this.current().innerText; + } else { + selectedValue = this.current().textContent; + } + + this.$editor.session.replace(range, selectedValue); + // Deactivate asynchrounously, so that in case of ENTER - we don't reactivate immediately. + setTimeout(function() { + _self.deactivate(); + }, 0); + }; this.deactivate = function() { - // Hide list - element.style.display = 'none'; - - // Restore keyboard - editor.session.setUseSoftTabs(originalSoftTabs); - editor.onTextInput = originalOnTextInput; + this.autocompleteContainer.parentNode.removeChild(this.autocompleteContainer); - self.active = false; - } + this.$editor.commands.commands.golineup.exec = this.originalGoLineUp; + this.$editor.commands.commands.golinedown.exec = this.originalGoLineDown; + this.$editor.commands.commands.indent.exec = this.originalIndent; + this.$editor.onTextInput = this.originalOnTextInput; + + this.active = false; + }; // Shows the list and reassigns keys this.activate = function(row, column) { - if(this.active) return; - this.active = true; - this.row = row; - this.column = column; + if (this.active) return; - // Position the list - var coords = this.editor.renderer.textToScreenCoordinates(row, column); - this.autocompleteContainer.style.top = coords.pageY + 18 + 'px'; - this.autocompleteContainer.style.left = coords.pageX + -2 + 'px'; - this.autocompleteContainer.style.display = 'block'; + var _self = this; + + this.active = true; + this.row = row; + this.column = column; + + // Position the list + var coords = this.$editor.renderer.textToScreenCoordinates(row, column); + this.autocompleteContainer.style.top = coords.pageY + 18 + "px"; + this.autocompleteContainer.style.left = coords.pageX + -2 + "px"; + this.autocompleteContainer.style.display = "block"; + + this.$editor.commands.commands.golinedown.exec = function(env, args, request) { _self.focusNext(); }; + this.$editor.commands.commands.golineup.exec = function(env, args, request) { _self.focusPrev(); }; + this.$editor.commands.commands.indent.exec = function(env, args, request) { _self.replace(); }; + + this.$editor.onTextInput = function(text) { + if (text == "\n") { + _self.replace(); + } else { + _self.originalOnTextInput.call(_self.$editor, text); + } + }; }; // Sets the text the suggest should be based on. // afterText indicates the position where the suggest box should start. this.suggest = function(text) { - var options = ["FUNK", "frunk", "blunk", "frunk", "blunk", "frunk", "blunk", "frunk", "blunk", "frunk", "blunk", "frunk", "blunk"];//matches(text); + var options = ["FUNK", "frunk", "blunk", "frunk", "blunk", "frunk", "blunk", "frunk", "blunk", "frunk", "blunk", "frunk", "blunk"]; if (options.length == 0) { return deactivate(); } @@ -139,12 +156,18 @@ var Autocomplete = function(editor) { var opt = this.selection.appendChild(document.createElement("option")); opt.appendChild(document.createTextNode(options[n])); } + this.selection.firstChild.selected = true; - this.selection.size = Math.min(10, options.length); + this.selection.size = Math.min(5, options.length); document.body.appendChild(this.autocompleteContainer); - //ensureFocus(); + this.ensureFocus(); }; + + this.isActive = function() { + return this.active; + }; + }).call(Autocomplete.prototype); exports.Autocomplete = Autocomplete; diff --git a/lib/ace/commands/command_manager.js b/lib/ace/commands/command_manager.js index b3e0fc6d..46a4b604 100644 --- a/lib/ace/commands/command_manager.js +++ b/lib/ace/commands/command_manager.js @@ -8,7 +8,7 @@ var EventEmitter = require("../lib/event_emitter").EventEmitter; /** * @class CommandManager * - * + * **/ /** @@ -16,9 +16,6 @@ var EventEmitter = require("../lib/event_emitter").EventEmitter; * @param {String} platform Identifier for the platform; must be either `'mac'` or `'win'` * @param {Array} commands A list of commands * - * - * - * **/ var CommandManager = function(platform, commands) { @@ -27,7 +24,7 @@ var CommandManager = function(platform, commands) { this.commmandKeyBinding = {}; this.addCommands(commands); - + this.setDefaultHandler("exec", function(e) { return e.command.exec(e.editor, e.args || {}); }); diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index 9d3bc401..bef4c0fc 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -307,6 +307,11 @@ exports.commands = [{ exec: function(editor) { editor.jumpToMatching(true); }, multiSelectAction: "forEach", readOnly: true +}, { + name: "hideautocomplete", + bindKey: bindKey("Esc", "Esc"), + exec: function(editor) { editor.$hideautocomplete(); }, + readOnly: true }, // commands disabled in readOnly mode diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 2e46aed0..08380311 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -90,7 +90,7 @@ var Editor = function(renderer, session) { }); this.setSession(session || new EditSession("")); - this.auto = new Autocomplete(this); + this.autocomplete = new Autocomplete(this); config.resetOptions(this); config._emit("editor", this); }; @@ -475,18 +475,24 @@ var Editor = function(renderer, session) { var source = this.session.getValue(); var _self = this; + setTimeout(function() { var cursor = _self.getCursorPosition(); var line = _self.session.getLine(cursor.row); - _self.auto.activate(cursor.row, cursor.column); - _self.auto.suggest(name); + _self.autocomplete.activate(cursor.row, cursor.column); + _self.autocomplete.suggest(name); }, 0); // update cursor because tab characters can influence the cursor position this.$cursorChange(); }; + this.$hideautocomplete = function() { + if (this.autocomplete.isActive()) + this.autocomplete.deactivate(); + }; + this.onTokenizerUpdate = function(e) { var rows = e.data; this.renderer.updateLines(rows.first, rows.last);