diff --git a/lib/ace/layer/cursor.js b/lib/ace/layer/cursor.js
index 7d1b7fa6..be444747 100644
--- a/lib/ace/layer/cursor.js
+++ b/lib/ace/layer/cursor.js
@@ -107,14 +107,8 @@ var Cursor = function(parentEl) {
top : 0
};
}
-
- var cursorLeft = Math.round(this.position.column * this.config.characterWidth);
- var cursorTop = this.position.row * this.config.lineHeight;
-
- return {
- left : cursorLeft,
- top : cursorTop
- };
+
+ return this.config.getPixelPosition(this.position.row, this.position.column);
};
this.update = function(config) {
@@ -123,17 +117,10 @@ var Cursor = function(parentEl) {
this.config = config;
- var cursorLeft = Math.round(this.position.column * config.characterWidth);
- var cursorTop = this.position.row * config.lineHeight;
+ this.pixelPos = this.getPixelPosition();
- this.pixelPos = {
- left : cursorLeft,
- top : cursorTop
- };
-
- this.cursor.style.left = cursorLeft + "px";
- this.cursor.style.top = (cursorTop - (config.firstRow * config.lineHeight))
- + "px";
+ this.cursor.style.left = this.pixelPos.left + "px";
+ this.cursor.style.top = this.pixelPos.top + "px";
this.cursor.style.width = config.characterWidth + "px";
this.cursor.style.height = config.lineHeight + "px";
diff --git a/lib/ace/layer/gutter.js b/lib/ace/layer/gutter.js
index 4202772f..e4591e01 100644
--- a/lib/ace/layer/gutter.js
+++ b/lib/ace/layer/gutter.js
@@ -71,7 +71,7 @@ var Gutter = function(parentEl) {
html.push("
", (i+1), "
");
+ "' style='height:", (config.wrapped[i].length + 1) * config.lineHeight, "px;'>", (i+1), "");
html.push("");
}
diff --git a/lib/ace/layer/marker.js b/lib/ace/layer/marker.js
index 06422bd5..be12014f 100644
--- a/lib/ace/layer/marker.js
+++ b/lib/ace/layer/marker.js
@@ -85,6 +85,10 @@ var Marker = function(parentEl) {
var range = marker.range.clipRows(config.firstRow, config.lastRow);
if (range.isEmpty()) continue;
+
+ // TODO: Add this conversion to the range object directly!
+ range.start = this.config.posToWrappedPos(range.start.row, range.start.column);
+ range.end = this.config.posToWrappedPos(range.end.row, range.end.column);
if (range.isMultiLine()) {
if (marker.type == "text") {
@@ -121,7 +125,8 @@ var Marker = function(parentEl) {
};
this.drawMultiLineMarker = function(stringBuilder, range, clazz, layerConfig) {
- var range = range.toScreenRange(this.doc);
+ // TODO: Add this back.
+ // var range = range.toScreenRange(this.doc);
// from selection start to the end of the line
var height = layerConfig.lineHeight;
@@ -163,7 +168,8 @@ var Marker = function(parentEl) {
};
this.drawSingleLineMarker = function(stringBuilder, range, clazz, layerConfig) {
- var range = range.toScreenRange(this.doc);
+ // TODO: Add this back.
+ //var range = range.toScreenRange(this.doc);
var height = layerConfig.lineHeight;
var width = Math.round((range.end.column - range.start.column) * layerConfig.characterWidth);
diff --git a/lib/ace/layer/text.js b/lib/ace/layer/text.js
index 98ff7bfc..371cd7e6 100644
--- a/lib/ace/layer/text.js
+++ b/lib/ace/layer/text.js
@@ -99,7 +99,7 @@ var Text = function(parentEl) {
style.width = style.height = "auto";
style.left = style.top = "-1000px";
-
+
style.visibility = "hidden";
style.position = "absolute";
style.overflow = "visible";
@@ -151,7 +151,7 @@ var Text = function(parentEl) {
this.updateLines = function(layerConfig, firstRow, lastRow) {
this.$computeTabString();
this.config = layerConfig;
-
+
var first = Math.max(firstRow, layerConfig.firstRow);
var last = Math.min(lastRow, layerConfig.lastRow);
@@ -166,6 +166,9 @@ var Text = function(parentEl) {
var html = [];
_self.$renderLine(html, i, tokens[i-first].tokens);
lineElement.innerHTML = html.join("");
+ // The height of the line might have changed if wrapped mode
+ // is active.
+ lineElement.style.height = (layerConfig.wrapped[i].length + 1) * layerConfig.lineHeight + "px";
}
});
};
@@ -226,7 +229,7 @@ var Text = function(parentEl) {
var lineEl = document.createElement("div");
lineEl.className = "ace_line";
var style = lineEl.style;
- style.height = _self.$characterSize.height + "px";
+ style.height = (config.wrapped[row].length + 1) * config.lineHeight + "px";
style.width = config.width + "px";
var html = [];
@@ -244,15 +247,20 @@ var Text = function(parentEl) {
var html = [];
var _self = this;
- this.tokenizer.getTokens(config.firstRow, config.lastRow, function(tokens) {
- for ( var i = config.firstRow; i <= config.lastRow; i++) {
- html.push("");
- _self.$renderLine(html, i, tokens[i-config.firstRow].tokens), html.push("
");
- }
-
- _self.element.innerHTML = html.join("");
+ this.$renderLinesFragment(config, config.firstRow, config.lastRow, function(fragment) {
+ // TODO: Use a proper method to remove all children of the element.
+ _self.element.innerHTML = "";
+ _self.element.appendChild(fragment);
});
+ // this.tokenizer.getTokens(config.firstRow, config.lastRow, function(tokens) {
+ // for ( var i = config.firstRow; i <= config.lastRow; i++) {
+ // html.push("");
+ // _self.$renderLine(html, i, tokens[i-config.firstRow].tokens), html.push("
");
+ // }
+ //
+ // _self.element.innerHTML = html.join("");
+ // });
};
this.$textToken = {
@@ -262,6 +270,8 @@ var Text = function(parentEl) {
};
this.$renderLine = function(stringBuilder, row, tokens) {
+ stringBuilder.push("");
+ var wrappedInfo = this.config.wrapped[row];
// if (this.$showInvisibles) {
// var self = this;
// var spaceRe = /[\v\f \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]+/g;
@@ -275,22 +285,48 @@ var Text = function(parentEl) {
var spaceReplace = " ";
// }
- for ( var i = 0; i < tokens.length; i++) {
- var token = tokens[i];
-
- var output = token.value
+ var _self = this;
+ function addToken(token, value) {
+ var output = value
.replace(/&/g, "&")
.replace(/", output, "");
}
else {
stringBuilder.push(output);
}
+ }
+
+ var chars = 0;
+ var wrapSection = 0;
+ var maxChars = wrappedInfo[wrapSection] || 9999;
+ var value;
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i];
+
+ if (chars + token.value.length < maxChars) {
+ addToken(token, token.value);
+ chars += token.value.length;
+ } else {
+ value = token.value;
+ while (chars + value.length >= maxChars) {
+ addToken(token, value.substring(0, maxChars - chars));
+ value = value.substring(maxChars - chars);
+ chars = maxChars;
+ stringBuilder.push("
");
+ wrapSection ++;
+ maxChars = wrappedInfo[wrapSection] || 9999;
+ }
+ if (value.length != 0) {
+ chars += value.length;
+ addToken(token, value);
+ }
+ }
};
if (this.$showInvisibles) {
@@ -300,6 +336,7 @@ var Text = function(parentEl) {
stringBuilder.push("" + this.EOF_CHAR + "");
}
}
+ stringBuilder.push("
");
};
}).call(Text.prototype);
diff --git a/lib/ace/virtual_renderer.js b/lib/ace/virtual_renderer.js
index 03c3322e..f3552a21 100644
--- a/lib/ace/virtual_renderer.js
+++ b/lib/ace/virtual_renderer.js
@@ -82,7 +82,7 @@ var VirtualRenderer = function(container, theme) {
this.$cursorLayer = new CursorLayer(this.content);
this.layers = [ this.$markerLayer, textLayer, this.$cursorLayer ];
-
+
this.scrollBar = new ScrollBar(container);
this.scrollBar.addEventListener("scroll", this.onScroll.bind(this));
@@ -118,6 +118,9 @@ var VirtualRenderer = function(container, theme) {
};
(function() {
+ this.layerConfig = {
+ wrapped: []
+ };
this.showGutter = true;
@@ -142,10 +145,26 @@ var VirtualRenderer = function(container, theme) {
this.$loop.schedule(this.CHANGE_FULL);
};
+ this.$updateWrappedLinesInfo = function(firstRow, lastRow) {
+ var WRAPSIZE = 12;
+ var wrappedInfo = this.layerConfig.wrapped;
+ var lines = this.lines;
+ for (var row = firstRow; row <= lastRow; row++) {
+ var col = 12;
+ wrappedInfo[row] = [];
+ while (col < lines[row].length) {
+ wrappedInfo[row].push(col);
+ col += 12;
+ }
+ }
+ };
+
/**
* Triggers partial update of the text layer
*/
this.updateLines = function(firstRow, lastRow) {
+ this.$updateWrappedLinesInfo(firstRow, lastRow);
+ console.log("updateLines", firstRow, lastRow);
if (lastRow === undefined)
lastRow = Infinity;
@@ -400,7 +419,7 @@ var VirtualRenderer = function(container, theme) {
var firstRow = Math.max(0, Math.round((this.scrollTop - offset) / this.lineHeight));
var lastRow = Math.max(0, Math.min(this.lines.length, firstRow + lineCount) - 1);
- var layerConfig = this.layerConfig = {
+ var layerConfig = oop.mixin(this.layerConfig, {
width : longestLine,
padding : this.$padding,
firstRow : firstRow,
@@ -410,7 +429,11 @@ var VirtualRenderer = function(container, theme) {
minHeight : minHeight,
offset : offset,
height : this.$size.scrollerHeight
- };
+ });
+
+ // Ensure that there is a wrapped array for all the rows in the current
+ // view port.
+ this.$updateWrappedLinesInfo(firstRow, lastRow);
for ( var i = 0; i < this.layers.length; i++) {
var layer = this.layers[i];
@@ -570,10 +593,12 @@ var VirtualRenderer = function(container, theme) {
var row = Math.floor((pageY + this.scrollTop - canvasPos.top)
/ this.lineHeight);
- return {
- row : row,
- column : this.doc.screenToDocumentColumn(Math.max(0, Math.min(row, this.doc.getLength()-1)), col)
- };
+ return this.layerConfig.wrappedPosToPos(
+ row,
+ col
+ // TODO: Figure out how to calculate tabs here...
+ //this.doc.screenToDocumentColumn(Math.max(0, Math.min(row, this.doc.getLength()-1)), col)
+ );
};
this.textToScreenCoordinates = function(row, column) {
@@ -587,6 +612,65 @@ var VirtualRenderer = function(container, theme) {
pageY: canvasPos.top + y - this.getScrollTop()
}
};
+
+ this.wrappedPosToPos = function(row, column) {
+ var linesCount = this.wrapped.length;
+ var realRow = 0;
+ while (realRow < linesCount && row >= this.wrapped[realRow].length + 1) {
+ row -= this.wrapped[realRow].length + 1;
+ realRow ++;
+ }
+ return {
+ row: realRow,
+ column: column + (realRow < linesCount ? this.wrapped[realRow][row - 1] || 0 : 0)
+ };
+ };
+
+ this.posToWrappedPos = function(row, column) {
+ // TODO: Why can it happen, that row is higher then the current count
+ // of lines (note lines in doc, not only in wrapped!). Happens when
+ // the cursor is in the last line and the marker "ace_active_line" is
+ // painted.
+ if (row > this.wrapped.length - 1) {
+ row = this.wrapped.length - 1;
+ column = 99999;
+ }
+
+ var rows = 0;
+ for (var i = 0; i < row; i++) {
+ rows += this.wrapped[i].length + 1;
+ }
+
+ var col = column;
+ for (var s = 0; s < this.wrapped[row].length; s++) {
+ if (column > this.wrapped[row][s]) {
+ col = column - this.wrapped[row][s];
+ rows ++;
+ } else {
+ break;
+ }
+ }
+ return {
+ row: rows,
+ column: col
+ };
+ };
+
+ this.getPixelPosition = function(row, column) {
+ var pos = this.posToWrappedPos(row, column);
+ var cursorLeft = Math.round(pos.column * this.characterWidth);
+ var cursorTop = pos.row * this.lineHeight;
+
+ return {
+ left : cursorLeft,
+ top : cursorTop
+ };
+ };
+
+ // TODO: This should get passed in a different way to the cursorLayer!
+ this.layerConfig.getPixelPosition = this.getPixelPosition;
+ this.layerConfig.posToWrappedPos = this.posToWrappedPos;
+ this.layerConfig.wrappedPosToPos = this.wrappedPosToPos;
this.visualizeFocus = function() {
dom.addCssClass(this.container, "ace_focus");
diff --git a/support/paths.js b/support/paths.js
index 1be92a90..552c7022 100644
--- a/support/paths.js
+++ b/support/paths.js
@@ -4,4 +4,5 @@ require.paths.unshift(__dirname + "/../plugins");
require.paths.unshift(__dirname + "/async/lib");
require.paths.unshift(__dirname + "/node-htmlparser/lib");
require.paths.unshift(__dirname + "/jsdom/lib");
+require.paths.unshift(__dirname + "/cockpit/support/pilot/lib");
require.paths.unshift(__dirname);