style improvements

This commit is contained in:
nightwing 2013-05-29 00:30:05 +04:00
commit f6f475747b
10 changed files with 243 additions and 233 deletions

View file

@ -155,7 +155,7 @@ env.editor.commands.addCommands([{
bindKey: "ctrl+enter",
exec: function(editor) {
try {
var r = eval(editor.getCopyText()||editor.getValue());
var r = window.eval(editor.getCopyText()||editor.getValue());
} catch(e) {
r = e;
}
@ -559,7 +559,7 @@ ace.commands.bindKey("Tab", function(editor) {
editor.execCommand("indent");
})
var Autocompleter = require("ace/autocomplete").Autocomplete;
Autocompleter.addTo(env.editor)
require("ace/ext/language_tools");
});

View file

@ -31,17 +31,18 @@
define(function(require, exports, module) {
"use strict";
var Range = require("./range").Range;
var HashHandler = require("./keyboard/hash_handler").HashHandler;
var AcePopup = require("./autocomplete/popup").AcePopup;
var util = require("./autocomplete/util");
var event = require("./lib/event");
var Autocomplete = function() {
this.keyboardHandler = new HashHandler();
this.keyboardHandler.bindKeys(this.commands);
this.$blurListener = this.blurListener.bind(this);
this.$changeListener = this.changeListener.bind(this);
this.$mousedownListener = this.mousedownListener.bind(this);
this.blurListener = this.blurListener.bind(this);
this.changeListener = this.changeListener.bind(this);
this.mousedownListener = this.mousedownListener.bind(this);
};
(function() {
@ -49,6 +50,7 @@ var Autocomplete = function() {
this.popup = new AcePopup(document.body || document.documentElement);
this.popup.on("click", function(e) {
this.insertMatch();
e.stop();
}.bind(this));
};
@ -56,12 +58,12 @@ var Autocomplete = function() {
if (!this.popup)
this.$init();
this.popup.setData(this.completions.filtered)
this.popup.setData(this.completions.filtered);
var renderer = editor.renderer;
var lineHeight = renderer.layerConfig.lineHeight;
var pos = renderer.$cursorLayer.getPixelPosition(null, true)
var rect = editor.container.getBoundingClientRect()
var pos = renderer.$cursorLayer.getPixelPosition(null, true);
var rect = editor.container.getBoundingClientRect();
pos.top += rect.top - renderer.layerConfig.offset;
pos.left += rect.left;
pos.left += renderer.$gutterLayer.gutterWidth;
@ -113,24 +115,26 @@ var Autocomplete = function() {
case "up": row = row <= 0 ? max : row - 1; break;
case "down": row = row >= max ? 0 : row + 1; break;
case "start": row = 0; break;
case "end": row = max; break
case "end": row = max; break;
}
this.popup.setRow(row);
};
this.insertMatch = function(row) {
this.insertMatch = function(data) {
this.detach();
if (row == undefined)
row = this.popup.getRow();
var text = this.completions.filtered[row];
if (text.value)
text = text.value;
// should be good enough, otherwise we can use getDocument().removeInLine
this.editor.removeWordLeft();
this.editor.insert(text);
if (!data)
data = this.popup.getData(this.popup.getRow());
if (!data)
return false;
if (data.completer && data.completer.insertMatch) {
data.completer.insertMatch(this.editor);
} else {
if (data.value)
data = data.value;
this.editor.removeWordLeft();
this.editor.insert(data);
}
};
this.commands = {
@ -149,11 +153,36 @@ var Autocomplete = function() {
"PageDown": function(editor) { editor.completer.popup.gotoPageUp(); }
};
this.getCompletions = function(editor, callback) {
var session = editor.getSession();
var pos = editor.getCursorPosition();
var line = session.getLine(pos.row);
var prefix = util.retrievePrecedingIdentifier(line, pos.column);
var matches = [];
util.parForEach(editor.completers, function(completer, next) {
completer.getCompletions(session, pos, prefix, function(err, results) {
if (!err)
matches = matches.concat(results);
next();
});
}, function() {
matches.sort(function(a, b) {
return b.score - a.score;
});
callback(null, {
prefix: prefix,
matches: matches
});
});
return true;
};
this.complete = function(editor) {
if (this.editor)
this.detach();
var _self = this;
this.editor = editor;
if (editor.completer != this) {
if (editor.completer)
@ -162,25 +191,35 @@ var Autocomplete = function() {
}
editor.keyBinding.addKeyboardHandler(this.keyboardHandler);
editor.on("changeSelection", this.$changeListener);
editor.on("blur", this.$blurListener);
editor.on("mousedown", this.$mousedownListener);
editor.on("changeSelection", this.changeListener);
editor.on("blur", this.blurListener);
editor.on("mousedown", this.mousedownListener);
//worker.attachToDocument(editor.session.getDocument(), {cursor: editor.getCursorPosition(), keywords: editor.session.getMode().getKeywords()}, true);
var matches = data.data.matches;
if (matches.length) {
_self.completions = new FilteredList(matches);
_self.completions.setFilter("a");
_self.openPopup(editor);
}
else {
_self.detach();
}
this.getCompletions(this.editor, function(err, results) {
var matches = results && results.matches;
if (!matches || !matches.length)
return this.detach();
if (matches.length == 1)
return this.insertMatch(matches[0]);
this.completions = new FilteredList(matches);
this.completions.setFilter(results.prefix);
this.openPopup(editor);
this.popup.setHighlight(results.prefix);
}.bind(this));
};
this.cancelContextMenu = function() {
var stop = function(e) {
this.editor.off("nativecontextmenu", stop);
if (e && e.domEvent)
event.stopEvent(e.domEvent);
}.bind(this);
setTimeout(stop, 10);
this.editor.on("nativecontextmenu", stop);
};
this.completers = [];
}).call(Autocomplete.prototype);
@ -191,12 +230,14 @@ Autocomplete.startCommand = {
editor.completer = new Autocomplete();
editor.completer.complete(editor);
editor.completer.activated = true;
// needed for firefox on mac
editor.completer.cancelContextMenu();
},
bindKey: "Ctrl-Space|Shift-Space|Alt-Space"
}
};
Autocomplete.addTo = function(editor) {
editor.commands.addCommand(Autocomplete.startCommand);
}
};
var FilteredList = function(array, mutateData) {
this.all = array;

View file

@ -33,34 +33,22 @@ define(function(require, exports, module) {
var EditSession = require("../edit_session").EditSession;
var Renderer = require("../virtual_renderer").VirtualRenderer;
var Editor = require("../editor").Editor;
var Range = require("../range").Range;
var event = require("../lib/event");
var lang = require("../lib/lang");
var dom = require("../lib/dom");
var $singleLineEditor = function(el) {
var renderer = new Renderer(el);
el.style.overflow = "hidden";
renderer.scrollBar.element.style.top = "0";
renderer.scrollBar.element.style.display = "none";
renderer.scrollBar.orginalWidth = renderer.scrollBar.width;
renderer.scrollBar.width = 0;
renderer.content.style.height = "auto";
renderer.screenToTextCoordinates = function(x, y) {
var pos = this.pixelToScreenCoordinates(x, y);
return this.session.screenToDocumentPosition(
Math.min(this.session.getScreenLength() - 1, Math.max(pos.row, 0)),
Math.max(pos.column, 0)
);
};
renderer.maxLines = 4;
renderer.$computeLayerConfigWithScroll = renderer.$computeLayerConfig;
renderer.scrollBar.orginalWidth = renderer.scrollBar.getWidth();
renderer.$computeLayerConfig = function() {
var config = this.layerConfig;
var height = this.session.getScreenLength() * this.lineHeight;
var maxHeight = this.maxLines * this.lineHeight
var desiredHeight = Math.max(this.lineHeight, Math.min(maxHeight, height))
var maxHeight = this.maxLines * this.lineHeight;
var desiredHeight = Math.max(this.lineHeight, Math.min(maxHeight, height));
var vScroll = height > maxHeight;
if (desiredHeight != this.desiredHeight || vScroll != this.$vScroll) {
if (vScroll != this.$vScroll) {
@ -83,15 +71,13 @@ var $singleLineEditor = function(el) {
this.container.style.height = desiredHeight + "px";
this.onResize();
this.$loop.changes = 0
this.$loop.changes = 0;
this.desiredHeight = desiredHeight;
this.scroller.style.overflowX="hidden"
this.scroller.style.overflowX = "hidden";
}
return renderer.$computeLayerConfigWithScroll();
};
var Editor = require("ace/editor").Editor;
var editor = new Editor(renderer);
editor.setHighlightActiveLine(false);
@ -121,7 +107,7 @@ var AcePopup = function(parentNode) {
popup.renderer.$cursorLayer.restartTimer = noop;
popup.renderer.$cursorLayer.element.style.opacity = 0;
popup.renderer.maxLines = 8
popup.renderer.maxLines = 8;
popup.renderer.$keepTextAreaAtCursor = false;
popup.setHighlightActiveLine(true);
@ -134,19 +120,6 @@ var AcePopup = function(parentNode) {
e.stop();
});
popup.getRow = function() {
var line = this.getCursorPosition().row;
if (line == 0 && !this.getHighlightActiveLine())
line = -1;
return line;
};
popup.setRow = function(line) {
popup.setHighlightActiveLine(line != -1);
popup.selection.clearSelection();
popup.moveCursorTo(line, 0 || 0);
};
var hoverMarker = new Range(-1,0,-1,Infinity);
hoverMarker.id = popup.session.addMarker(hoverMarker, "ace_line-hover", "fullLine");
popup.on("mousemove", function(e) {
@ -165,14 +138,9 @@ var AcePopup = function(parentNode) {
popup.on("mousewheel", function(e) {
setTimeout(function() {
popup._signal("mousemove", e);
})
});
});
popup.data = []
popup.setData = function(list) {
popup.data = list || [];
popup.setValue(lang.stringRepeat("\n", list.length), -1);
};
popup.session.doc.getLength = function() {
return popup.data.length;
};
@ -183,26 +151,51 @@ var AcePopup = function(parentNode) {
return (data && data.value) || "";
};
var bgTokenizer = popup.session.bgTokenizer
var bgTokenizer = popup.session.bgTokenizer;
bgTokenizer.$tokenizeRow = function(i) {
var data = popup.data[i];
var tokens = [];
if (!data)
return tokens;
if (typeof data == "string")
data = {type: data, value: data}//return [{type: "", value: data}];
data = {value: data};
tokens.push({type: "", value: data.value});
if (data.type) {
tokens.push({type: data.className || "", value: data.value});
if (data.meta) {
var maxW = popup.renderer.$size.scrollerWidth / popup.renderer.layerConfig.characterWidth;
if (data.type.length + data.value.length < maxW - 2)
tokens.push({type: "rightAlignedText", value: data.type});
if (data.meta.length + data.value.length < maxW - 2)
tokens.push({type: "rightAlignedText", value: data.meta});
}
return tokens;
};
bgTokenizer.$updateOnChange = noop
bgTokenizer.$updateOnChange = noop;
popup.session.$computeWidth = function() {
return this.screenWidth = 0;
}
// public
popup.data = [];
popup.setData = function(list) {
popup.data = list || [];
popup.setValue(lang.stringRepeat("\n", list.length), -1);
};
popup.getData = function(row) {
return popup.data[row];
};
popup.getRow = function() {
var line = this.getCursorPosition().row;
if (line == 0 && !this.getHighlightActiveLine())
line = -1;
return line;
};
popup.setRow = function(line) {
popup.setHighlightActiveLine(line != -1);
popup.selection.clearSelection();
popup.moveCursorTo(line, 0 || 0);
};
// highlight
popup.setHighlight = function(re) {
popup.session.highlight(re);
popup.session._emit("changeFrontMarker");
@ -211,24 +204,24 @@ var AcePopup = function(parentNode) {
popup.hide = function() {
this.container.style.display = "none";
this._signal("hide");
}
};
popup.show = function(pos, lineHeight) {
var el = this.container;
if (pos.top > window.innerHeight / 2 + lineHeight) {
el.style.top = ""
el.style.top = "";
el.style.bottom = window.innerHeight - pos.top + "px";
} else {
pos.top += lineHeight;
el.style.top = pos.top + "px";
el.style.bottom = ""
el.style.bottom = "";
}
el.style.left = pos.left + "px";
el.style.display = "";
this._signal("show");
}
};
return popup;
};
@ -257,6 +250,7 @@ dom.importCssString("\
background: #f8f8f8;\
border: 1px lightgray solid;\
position: fixed;\
box-shadow: 2px 3px 5px rgba(0,0,0,.2);\
}");
exports.AcePopup = AcePopup;

View file

@ -29,69 +29,61 @@
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var completeUtil = require("./complete_util");
var SPLIT_REGEX = /[^a-zA-Z_0-9\$]+/;
var MAX_SCORE = 1000000;
var Range = require("ace/range").Range;
var splitRegex = /[^a-zA-Z_0-9\$\-]+/;
var completer = module.exports;
// For the current document, gives scores to identifiers not on frequency, but on distance from the current prefix
function wordDistanceAnalyzer(doc, pos, prefix, keywords) {
var text = doc.getValue().trim();
// Determine cursor's word index
var textBefore = doc.getLines(0, pos.row - 1).join("\n") + "\n";
var currentLine = doc.getLine(pos.row);
textBefore += currentLine.substr(0, pos.column);
var prefixPosition = textBefore.trim().split(SPLIT_REGEX).length - 1;
// Split entire document into words
var identifiers = text.split(SPLIT_REGEX);
var identDict = {};
// Find prefix to find other identifiers close it
for (var i = 0; i < identifiers.length; i++) {
if (i === prefixPosition)
continue;
var ident = identifiers[i];
if (ident.length === 0)
continue;
var distance = Math.max(prefixPosition, i) - Math.min(prefixPosition, i);
// Score substracted from MAX to force descending ordering
if (Object.prototype.hasOwnProperty.call(identDict, ident))
identDict[ident] = Math.max(MAX_SCORE - distance, identDict[ident]);
else
identDict[ident] = MAX_SCORE - distance;
}
for (var k = 0, l = keywords.length; k < l; k++) {
identDict[keywords[k]] = MAX_SCORE;
}
return identDict;
function getWordIndex(doc, pos) {
var textBefore = doc.getTextRange(Range.fromPoints({row: 0, column:0}, pos));
return textBefore.split(splitRegex).length - 1;
}
completer.complete = function(doc, pos, keywords, callback) {
var line = doc.getLine(pos.row);
var identifier = completeUtil.retrievePrecedingIdentifier(line, pos.column);
// there's nothing to autocomplete
if (identifier === "")
return callback(null);
var identDict = wordDistanceAnalyzer(doc, pos, identifier, keywords);
var allIdentifiers = [];
for (var ident in identDict) {
allIdentifiers.push(ident);
// NOTE: Naive implementation O(n), can be O(log n) with binary search
function filterPrefix(prefix, words) {
var results = [];
for (var i = 0; i < words.length; i++) {
if (words[i].indexOf(prefix) === 0) {
results.push(words[i]);
}
}
return results;
}
allIdentifiers = completeUtil.removeDuplicateWords(allIdentifiers);
/**
* Does a distance analysis of the word `prefix` at position `pos` in `doc`.
* @return Map
*/
function wordDistance(doc, pos) {
var prefixPos = getWordIndex(doc, pos);
var words = doc.getValue().split(splitRegex);
var wordScores = Object.create(null);
var currentWord = words[prefixPos];
// find fuzzy matches based on text in doc, as well as mode keywords
var matches = completeUtil.findCompletions(identifier, identDict, allIdentifiers);
words.forEach(function(word, idx) {
if (!word || word === currentWord) return;
callback(identifier, matches);
var distance = Math.abs(prefixPos - idx);
var score = words.length - distance;
if (wordScores[word]) {
wordScores[word] = Math.max(score, wordScores[word]);
} else {
wordScores[word] = score;
}
});
return wordScores;
}
exports.getCompletions = function(session, pos, prefix, callback) {
var wordScore = wordDistance(session, pos, prefix);
var wordList = filterPrefix(prefix, Object.keys(wordScore));
callback(null, wordList.map(function(word) {
return {
name: word,
value: word,
score: wordScore[word],
meta: "local"
};
}));
};
});

View file

@ -29,10 +29,25 @@
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
exports.parForEach = function(array, fn, callback) {
var completed = 0;
var arLength = array.length;
if (arLength === 0)
callback();
for (var i = 0; i < arLength; i++) {
fn(array[i], function(result, err) {
completed++;
if (completed === arLength)
callback(result, err);
});
}
}
var ID_REGEX = /[a-zA-Z_0-9\$]/;
function retrievePrecedingIdentifier(text, pos, regex) {
exports.retrievePrecedingIdentifier = function(text, pos, regex) {
regex = regex || ID_REGEX;
var buf = [];
for (var i = pos-1; i >= 0; i--) {
@ -44,7 +59,7 @@ function retrievePrecedingIdentifier(text, pos, regex) {
return buf.reverse().join("");
}
function retrieveFollowingIdentifier(text, pos, regex) {
exports.retrieveFollowingIdentifier = function(text, pos, regex) {
regex = regex || ID_REGEX;
var buf = [];
for (var i = pos; i < text.length; i++) {
@ -56,73 +71,4 @@ function retrieveFollowingIdentifier(text, pos, regex) {
return buf;
}
// filched from jQuery
function grep( elems, callback, inv ) {
var retVal,
ret = [],
i = 0,
length = elems.length;
inv = !!inv;
// Go through the array, only saving the items
// that pass the validator function
for ( ; i < length; i++ ) {
retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {
ret.push( elems[ i ] );
}
}
return ret;
};
function sortByScore(items, identDict) {
return items.sort(function(a, b) {
var scoreA = identDict[a],
scoreB = identDict[b];
if (a < b)
return 1;
else if (a > b)
return -1;
else
return 0;
});
};
function findCompletions(prefix, identDict, allIdentifiers) {
var _self = this,
fuzzyMatcher = function (prefix, item) {
return ~item.toLowerCase().indexOf(prefix.toLowerCase());
};
var matches = grep(allIdentifiers, function (item) {
return fuzzyMatcher(prefix, item);
});
matches = sortByScore(matches, identDict);
return matches;
}
exports.removeDuplicateWords = function(matches) {
// First, sort
matches = matches.sort();
for (var i = 1; i < matches.length; ){
if (matches[i - 1] == matches[i]){
matches.splice(i, 1);
} else {
i++;
}
}
return matches;
};
exports.retrievePrecedingIdentifier = retrievePrecedingIdentifier;
exports.retrieveFollowingIdentifier = retrieveFollowingIdentifier;
exports.findCompletions = findCompletions;
});

View file

@ -208,7 +208,7 @@ var optionsProvider = {
return;
var opt = this.$options[name];
if (!opt)
return undefined;
return false;
if (opt.forwardTo)
return this[opt.forwardTo] && this[opt.forwardTo].setOption(name, value);
@ -220,7 +220,7 @@ var optionsProvider = {
getOption: function(name) {
var opt = this.$options[name];
if (!opt)
return undefined;
return false;
if (opt.forwardTo)
return this[opt.forwardTo] && this[opt.forwardTo].getOption(name);
return opt && opt.get ? opt.get.call(this) : this["$" + name];

View file

@ -34,11 +34,47 @@ define(function(require, exports, module) {
var snippetManager = require("../snippets").snippetManager;
var Autocomplete = require("../autocomplete").Autocomplete;
var completers = [];
var textCompleter = require("../autocomplete/text_completer");
var completers = [textCompleter];
exports.addCompleter = function(completer) {
completers.push(completer);
};
exports.completers = {}
var expandSnippet = {
name: "expandSnippet",
exec: function(editor) {
var success = snippetManager.expandWithTab(editor);
if (!success)
editor.execCommand("indent");
},
bindKey: "tab"
}
var Editor = require("../editor").Editor;
require("../config").defineOptions(Editor.prototype, "editor", {
enableBasicAutocompletion: {
set: function(val) {
if (val) {
this.completers = completers
this.commands.addCommand(Autocomplete.startCommand);
} else {
this.commands.removeCommand(Autocomplete.startCommand);
}
},
value: true
},
enableSnippets: {
set: function(val) {
if (val) {
this.commands.addCommand(expandSnippet);
} else {
this.commands.removeCommand(expandSnippet);
}
},
value: true
}
});
});

View file

@ -40,8 +40,8 @@ var BROKEN_SETDATA = useragent.isChrome < 18;
var TextInput = function(parentNode, host) {
var text = dom.createElement("textarea");
text.className = "ace_text-input";
/*/ debug
text.style.cssText = "opacity:1;background:rgba(0, 250, 0, 0.3);outline:rgba(0, 250, 0, 0.8) solid 1px;outline-offset:3px;width:5em;z-index:500";
// debug
text.style.cssText = "opacity:1;background:rgba(0, 250, 0, 0.3);outline:rgba(0, 250, 0, 0.8) solid 1px;outline-offset:3px;width:5em;z-pindex:500";
/**/
if (useragent.isTouchPad)
text.setAttribute("x-palm-disable-auto-cap", true);
@ -436,10 +436,10 @@ var TextInput = function(parentNode, host) {
tempStyle = text.style.cssText;
text.style.cssText = "z-index:100000;" + (useragent.isIE ? "opacity:0.1;" : "");
// text.style.cssText += "background:rgba(250, 0, 0, 0.3); opacity:1;";
text.style.cssText += "background:rgba(250, 0, 0, 0.3); opacity:1;";
resetSelection(host.selection.isEmpty());
host._emit("nativecontextmenu", {target: host});
host._emit("nativecontextmenu", {target: host, domEvent: e});
var rect = host.container.getBoundingClientRect();
var style = dom.computedStyle(host.container);
var top = rect.top + (parseInt(style.borderTopWidth) || 0);
@ -477,7 +477,7 @@ var TextInput = function(parentNode, host) {
}
// firefox fires contextmenu event after opening it
if (!useragent.isGecko) {
if (!useragent.isGecko || useragent.isMac) {
event.addListener(text, "contextmenu", function(e) {
host.textInput.onContextMenu(e);
onContextMenuClose();

View file

@ -41,7 +41,7 @@ var oop = require("../lib/oop");
function Mode() {
var highlighter = new Rules();
this.$tokenizer = new Tokenizer(highlighter.getRules());
this.$keywordList = new Rules(rules.$keywordList);
this.$keywordList = new Rules(highlighter.$keywordList);
this.foldingRules = new FoldMode();
}

View file

@ -247,6 +247,7 @@ var themes = {
"pastel_on_dark": "Pastels on Dark",
"solarized_dark": "Solarized-dark",
"solarized_light": "Solarized-light",
"katzenmilch": "Katzenmilch",
//"textmate": "Textmate (Mac Classic)",
"tomorrow": "Tomorrow",
"tomorrow_night": "Tomorrow-Night",