Implement keybindings and such

This commit is contained in:
Garen Torikian 2012-12-22 11:26:57 -08:00 • committed by nightwing
commit dbca4444bf
4 changed files with 88 additions and 57 deletions

View file

@ -32,14 +32,16 @@ define(function(require, exports, module) {
"use strict"; "use strict";
var oop = require("./lib/oop"); var oop = require("./lib/oop");
var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require('ace/range').Range;
var Autocomplete = function(editor) { var Autocomplete = function(editor) {
var self = this; var self = this;
this.editor = editor; this.$editor = editor;
var originalOnTextInput = editor.onTextInput; this.originalGoLineUp = editor.commands.commands.golineup.exec;
var originalSoftTabs = editor.session.getUseSoftTabs(); this.originalGoLineDown = editor.commands.commands.golinedown.exec;
this.originalIndent = editor.commands.commands.indent.exec;
this.originalOnTextInput = editor.onTextInput;
// Create the suggest list // Create the suggest list
this.autocompleteContainer = document.createElement('div'); this.autocompleteContainer = document.createElement('div');
@ -51,86 +53,101 @@ var Autocomplete = function(editor) {
(function() { (function() {
oop.implement(this, EventEmitter);
this.current = function() { this.current = function() {
var children = element.childNodes; var children = this.selection.childNodes;
for (var i = 0; i < children.length; i++) { for (var i = 0; i < children.length; i++) {
var li = children[i]; var li = children[i];
if(li.className == 'ace_autocomplete_selected') { if (li.className == 'ace_autocomplete_selected') {
return li; return li;
} }
}; };
} }
this.focusNext = function() { this.focusNext = function() {
var curr = current(); var curr = this.current();
curr.className = ''; curr.className = '';
var focus = curr.nextSibling || curr.parentNode.firstChild; var focus = curr.nextSibling || curr.parentNode.firstChild;
focus.className = 'ace_autocomplete_selected'; focus.className = 'ace_autocomplete_selected';
focus.selected = true;
} }
this.focusPrev = function() { this.focusPrev = function() {
var curr = current(); var curr = this.current();
curr.className = ''; curr.className = '';
var focus = curr.previousSibling || curr.parentNode.lastChild; var focus = curr.previousSibling || curr.parentNode.lastChild;
focus.className = 'ace_autocomplete_selected'; focus.className = 'ace_autocomplete_selected';
focus.selected = true;
} }
this.ensureFocus = function() { this.ensureFocus = function() {
if(!current()) { if(!this.current()) {
element.firstChild.className = 'ace_autocomplete_selected'; this.selection.firstChild.className = 'ace_autocomplete_selected';
} }
} }
this.replace = function() { this.replace = function() {
var Range = require('ace/range').Range; var _self = this;
var range = new Range(self.row, self.column, self.row, self.column + 1000);
// Firefox does not support innerText property, don't know about IE var range = new Range(this.row, this.column, this.row, this.column + 1000);
// http://blog.coderlab.us/2005/09/22/using-the-innertext-property-with-firefox/
var selectedValue; var selectedValue;
if(document.all){ if (document.all) {
selectedValue = current().innerText; selectedValue = this.current().innerText;
} else{ } else {
selectedValue = current().textContent; selectedValue = this.current().textContent;
} }
editor.session.replace(range, selectedValue); this.$editor.session.replace(range, selectedValue);
// Deactivate asynchrounously, so that in case of ENTER - we don't reactivate immediately. // Deactivate asynchrounously, so that in case of ENTER - we don't reactivate immediately.
setTimeout(function() { setTimeout(function() {
deactivate(); _self.deactivate();
}, 0); }, 0);
} };
this.deactivate = function() { this.deactivate = function() {
// Hide list this.autocompleteContainer.parentNode.removeChild(this.autocompleteContainer);
element.style.display = 'none';
// Restore keyboard this.$editor.commands.commands.golineup.exec = this.originalGoLineUp;
editor.session.setUseSoftTabs(originalSoftTabs); this.$editor.commands.commands.golinedown.exec = this.originalGoLineDown;
editor.onTextInput = originalOnTextInput; this.$editor.commands.commands.indent.exec = this.originalIndent;
this.$editor.onTextInput = this.originalOnTextInput;
self.active = false; this.active = false;
} };
// Shows the list and reassigns keys // Shows the list and reassigns keys
this.activate = function(row, column) { this.activate = function(row, column) {
if(this.active) return; if (this.active) return;
var _self = this;
this.active = true; this.active = true;
this.row = row; this.row = row;
this.column = column; this.column = column;
// Position the list // Position the list
var coords = this.editor.renderer.textToScreenCoordinates(row, column); var coords = this.$editor.renderer.textToScreenCoordinates(row, column);
this.autocompleteContainer.style.top = coords.pageY + 18 + 'px'; this.autocompleteContainer.style.top = coords.pageY + 18 + "px";
this.autocompleteContainer.style.left = coords.pageX + -2 + 'px'; this.autocompleteContainer.style.left = coords.pageX + -2 + "px";
this.autocompleteContainer.style.display = 'block'; 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. // Sets the text the suggest should be based on.
// afterText indicates the position where the suggest box should start. // afterText indicates the position where the suggest box should start.
this.suggest = function(text) { 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) { if (options.length == 0) {
return deactivate(); return deactivate();
} }
@ -139,12 +156,18 @@ var Autocomplete = function(editor) {
var opt = this.selection.appendChild(document.createElement("option")); var opt = this.selection.appendChild(document.createElement("option"));
opt.appendChild(document.createTextNode(options[n])); opt.appendChild(document.createTextNode(options[n]));
} }
this.selection.firstChild.selected = true; 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); document.body.appendChild(this.autocompleteContainer);
//ensureFocus(); this.ensureFocus();
}; };
this.isActive = function() {
return this.active;
};
}).call(Autocomplete.prototype); }).call(Autocomplete.prototype);
exports.Autocomplete = Autocomplete; exports.Autocomplete = Autocomplete;

View file

@ -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 {String} platform Identifier for the platform; must be either `'mac'` or `'win'`
* @param {Array} commands A list of commands * @param {Array} commands A list of commands
* *
*
*
*
**/ **/
var CommandManager = function(platform, commands) { var CommandManager = function(platform, commands) {

View file

@ -307,6 +307,11 @@ exports.commands = [{
exec: function(editor) { editor.jumpToMatching(true); }, exec: function(editor) { editor.jumpToMatching(true); },
multiSelectAction: "forEach", multiSelectAction: "forEach",
readOnly: true readOnly: true
}, {
name: "hideautocomplete",
bindKey: bindKey("Esc", "Esc"),
exec: function(editor) { editor.$hideautocomplete(); },
readOnly: true
}, },
// commands disabled in readOnly mode // commands disabled in readOnly mode

View file

@ -90,7 +90,7 @@ var Editor = function(renderer, session) {
}); });
this.setSession(session || new EditSession("")); this.setSession(session || new EditSession(""));
this.auto = new Autocomplete(this); this.autocomplete = new Autocomplete(this);
config.resetOptions(this); config.resetOptions(this);
config._emit("editor", this); config._emit("editor", this);
}; };
@ -475,18 +475,24 @@ var Editor = function(renderer, session) {
var source = this.session.getValue(); var source = this.session.getValue();
var _self = this; var _self = this;
setTimeout(function() { setTimeout(function() {
var cursor = _self.getCursorPosition(); var cursor = _self.getCursorPosition();
var line = _self.session.getLine(cursor.row); var line = _self.session.getLine(cursor.row);
_self.auto.activate(cursor.row, cursor.column); _self.autocomplete.activate(cursor.row, cursor.column);
_self.auto.suggest(name); _self.autocomplete.suggest(name);
}, 0); }, 0);
// update cursor because tab characters can influence the cursor position // update cursor because tab characters can influence the cursor position
this.$cursorChange(); this.$cursorChange();
}; };
this.$hideautocomplete = function() {
if (this.autocomplete.isActive())
this.autocomplete.deactivate();
};
this.onTokenizerUpdate = function(e) { this.onTokenizerUpdate = function(e) {
var rows = e.data; var rows = e.data;
this.renderer.updateLines(rows.first, rows.last); this.renderer.updateLines(rows.first, rows.last);