Merge remote branch 'upstream/master' into requirejs

This commit is contained in:
Irakli Gozalishvili 2011-01-29 01:03:32 +01:00
commit bfdcc1e5b4
32 changed files with 1394 additions and 696 deletions

View file

@ -91,7 +91,7 @@ copy({
{
root: aceHome + '/lib',
include: /.*\.js$/,
exclude: /tests?\/|theme\/|mode\/|ace\/worker\/host\.js/
exclude: /tests?\/|theme\/|mode\/|ace\/worker\/worker\.js/
},
{ base: aceHome + '/lib/', path: 'ace/theme/textmate.js' },
{ base: aceHome + '/lib/', path: 'ace/mode/text.js' },
@ -128,6 +128,17 @@ copy({
dest: data
});
// Create the compressed and uncompressed output files
copy({
source: data,
//filter: copy.filter.uglifyjs,
dest: 'build/ace.js'
});
//copy({
// source: data,
// dest: 'build/ace-uncompressed.js'
//});
copy({
source: [
'build_support/editor.html'
@ -135,27 +146,51 @@ copy({
dest: 'build/editor.html'
});
// Create the compressed and uncompressed output files
copy({
source: data,
//filter: copy.filter.uglifyjs,
dest: 'build/ace.js'
});
copy({
source: data,
dest: 'build/ace-uncompressed.js'
});
// Create worker bootstrap code
copy({
source: "lib/ace/worker/host.js",
source: "lib/ace/worker/worker.js",
filter: [function(data) {
return data + "\nimportScripts('ace-uncompressed.js')";
return data + "\nimportScripts('ace.js')";
}],
dest: 'build/host.js'
dest: 'build/worker.js'
});
var eclipseTheme = copy.createDataObject();
copy({
source: [{
root: aceHome + '/lib',
include: "ace/theme/eclipse.js"
}],
filter: [ copy.filter.moduleDefines ],
dest: eclipseTheme
});
copy({
source: [{
root: aceHome + '/lib',
include: "ace/theme/eclipse.css"
}],
filter: [ copy.filter.addDefines ],
dest: eclipseTheme
});
copy({
source: eclipseTheme,
dest: 'build/theme/eclipse.js'
});
[
"clouds", "clouds_midnight", "cobalt", "dawn", "idle_fingers", "kr_theme",
"mono_industrial", "monokai", "pastel_on_dark", "twilight"
].forEach(function(theme) {
copy({
source: [{
root: aceHome + '/lib',
include: "ace/theme/" + theme + ".js"
}],
filter: [ copy.filter.moduleDefines ],
dest: "build/theme/" + theme + ".js"
});
});
function internalRequire(ignore) {
var exports = {};

View file

@ -38,42 +38,47 @@
// don't define it in a worker.
if (window.document) {
var deps = [ "pilot/fixoldbrowsers", "pilot/plugin_manager", "pilot/settings",
"pilot/environment" ];
require("pilot/fixoldbrowsers");
require("pilot/settings");
var Event = require("pilot/event");
var Dom = require("pilot/dom");
var EditSession = require("ace/edit_session").EditSession;
var JavaScriptMode = require("ace/mode/javascript").Mode;
var UndoManager = require("ace/undomanager").UndoManager;
var Editor = require("ace/editor").Editor;
var Renderer = require("ace/virtual_renderer").VirtualRenderer;
var Theme = require("ace/theme/textmate");
var catalog = require("pilot/plugin_manager").catalog;
catalog.registerPlugins([ "pilot/index" ]);
require(deps, function() {
var catalog = require("pilot/plugin_manager").catalog;
catalog.registerPlugins([ "pilot/index" ]);
});
var ace = {
edit: function(el) {
if (typeof(el) == "string") {
el = document.getElementById(el);
}
var doc = new EditSession(Dom.getInnerText(el));
doc.setMode(new JavaScriptMode());
doc.setUndoManager(new UndoManager());
el.innerHTML = '';
var editor = new Editor(new Renderer(el, "ace/theme/textmate"));
editor.setSession(doc);
var env = require("pilot/environment").create();
var catalog = require("pilot/plugin_manager").catalog;
catalog.startupPlugins({ env: env }).then(function() {
var EditSession = require("ace/edit_session").EditSession;
var JavaScriptMode = require("ace/mode/javascript").Mode;
var UndoManager = require("ace/undomanager").UndoManager;
var Editor = require("ace/editor").Editor;
var Renderer = require("ace/virtual_renderer").VirtualRenderer;
var theme = require("ace/theme/textmate");
var doc = new EditSession(el.innerHTML);
el.innerHTML = '';
doc.setMode(new JavaScriptMode());
doc.setUndoManager(new UndoManager());
env.document = doc;
env.editor = new Editor(new Renderer(el, theme));
env.editor.setSession(doc);
env.editor.resize();
window.addEventListener("resize", function() {
env.editor.resize();
}, false);
env.editor = env;
editor.resize();
Event.addListener(window, "resize", function() {
editor.resize();
});
el.env = env;
});
return editor;
}
};
}

View file

@ -17,11 +17,13 @@
}
}</div>
<script src="ace-uncompressed.js" type="text/javascript" charset="utf-8"></script>
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
<script src="theme/twilight.js" type="text/javascript" charset="utf-8"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
ace.edit("editor");
}, false);
document.addEventListener("DOMContentLoaded", function() {
var editor = ace.edit("editor");
editor.setTheme("ace/theme/twilight");
}, false);
</script>
</body>

View file

@ -44,7 +44,7 @@ exports.launch = function(env) {
var event = require("pilot/event");
var Editor = require("ace/editor").Editor;
var Renderer = require("ace/virtual_renderer").VirtualRenderer;
var theme = require("ace/theme/textmate");
var theme = require("ace/theme/textmate");
var EditSession = require("ace/edit_session").EditSession;
var JavaScriptMode = require("ace/mode/javascript").Mode;
var CssMode = require("ace/mode/css").Mode;
@ -58,43 +58,34 @@ exports.launch = function(env) {
var vim = require("ace/keyboard/keybinding/vim").Vim;
var emacs = require("ace/keyboard/keybinding/emacs").Emacs;
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
var keybindings = {
// Null = use "default" keymapping
ace: null,
vim: vim,
emacs: emacs,
// This is a way to define simple keyboard remappings
custom: new HashHandler({
"gotoright": "Tab"
})
}
var docs = {};
// Make the lorem ipsum text a little bit longer.
var loreIpsum = document.getElementById("plaintext").innerHTML;
for (var i = 0; i < 5; i++) {
loreIpsum += loreIpsum;
}
docs.plain = new EditSession(loreIpsum);
docs.plain.setUseWrapMode(true);
docs.plain.setMode(new TextMode());
docs.plain.setUndoManager(new UndoManager());
docs.js = new EditSession(document.getElementById("jstext").innerHTML);
docs.js.setMode(new JavaScriptMode());
docs.js.setUndoManager(new UndoManager());
if (false && window.Worker) {
var worker = new WorkerClient("../..", ["ace", "pilot"], "ace/worker/mirror", "Mirror");
worker.call("setValue", [docs.js.getValue()]);
docs.js.getDocument().on("change", function(e) {
e.range = {
start: e.data.range.start,
end: e.data.range.end
};
worker.emit("change", e);
});
worker.on("jslint", function(results) {
var errors = [];
for (var i=0; i<results.data.length; i++) {
var error = results.data[i];
if (error)
errors.push({
row: error.line-1,
column: error.character-1,
text: error.reason,
type: "error",
lint: error
})
}
docs.js.setAnnotations(errors)
});
};
docs.css = new EditSession(document.getElementById("csstext").innerHTML);
docs.css.setMode(new CssMode());
docs.css.setUndoManager(new UndoManager());
@ -114,7 +105,7 @@ exports.launch = function(env) {
var container = document.getElementById("editor");
env.editor = new Editor(new Renderer(container, theme));
var modes = {
text: new TextMode(),
xml: new XmlMode(),
@ -129,29 +120,13 @@ exports.launch = function(env) {
return modes[modeEl.value];
}
var modeEl = document.getElementById("mode");
function setMode() {
env.editor.getSession().setMode(modes[modeEl.value] || modes.text);
}
modeEl.onchange = setMode;
setMode();
var wrapModeEl = document.getElementById("soft_wrap");
// This is how you can set a custom keyboardHandler.
//
// Define some basic keymapping using a hash:
// env.editor.setKeyboardHandler(new HashHandler({
// "gotoright": "Tab"
// }));
//
// Use a more complex keymapping:
// env.editor.setKeyboardHandler(vim);
var docEl = document.getElementById("doc");
function onDocChange() {
var doc = docs[docEl.value];
bindDropdown("doc", function(value) {
var doc = docs[value];
env.editor.setSession(doc);
var mode = doc.getMode();
if (mode instanceof JavaScriptMode) {
modeEl.value = "javascript";
@ -174,62 +149,93 @@ exports.launch = function(env) {
else {
modeEl.value = "text";
}
env.editor.focus();
}
docEl.onchange = onDocChange;
onDocChange();
var themeEl = document.getElementById("theme");
function setTheme() {
env.editor.setTheme(themeEl.value);
};
themeEl.onchange = setTheme;
setTheme();
var selectEl = document.getElementById("select_style");
function setSelectionStyle() {
if (selectEl.checked) {
env.editor.setSelectionStyle("line");
if (!doc.getUseWrapMode()) {
wrapModeEl.value = "off";
} else {
env.editor.setSelectionStyle("text");
wrapModeEl.value = doc.getWrapLimit();
}
};
selectEl.onclick = setSelectionStyle;
setSelectionStyle();
env.editor.focus();
});
bindDropdown("mode", function(value) {
env.editor.getSession().setMode(modes[value] || modes.text);
});
var activeEl = document.getElementById("highlight_active");
function setHighlightActiveLine() {
env.editor.setHighlightActiveLine(!!activeEl.checked);
};
activeEl.onclick = setHighlightActiveLine;
setHighlightActiveLine();
bindDropdown("theme", function(value) {
env.editor.setTheme(value);
});
bindDropdown("keybinding", function(value) {
env.editor.setKeyboardHandler(keybindings[value]);
});
var showHiddenEl = document.getElementById("show_hidden");
function setShowInvisibles() {
env.editor.setShowInvisibles(!!showHiddenEl.checked);
};
showHiddenEl.onclick = setShowInvisibles;
setShowInvisibles();
bindDropdown("fontsize", function(value) {
document.getElementById("editor").style.fontSize = value;
});
bindDropdown("soft_wrap", function(value) {
var session = env.editor.getSession();
var renderer = env.editor.renderer;
switch (value) {
case "off":
session.setUseWrapMode(false);
renderer.setPrintMarginColumn(80);
break;
case "40":
session.setUseWrapMode(true);
session.setWrapLimit(40);
renderer.setPrintMarginColumn(40);
break;
case "80":
session.setUseWrapMode(true);
session.setWrapLimit(80);
renderer.setPrintMarginColumn(80);
break;
}
});
// for debugging
window.jump = function() {
var jump = document.getElementById("jump");
var cursor = env.editor.getCursorPosition();
var pos = env.editor.renderer.textToScreenCoordinates(cursor.row, cursor.column);
jump.style.left = pos.pageX + "px";
jump.style.top = pos.pageY + "px";
jump.style.display = "block";
};
bindCheckbox("select_style", function(checked) {
env.editor.setSelectionStyle(checked ? "line" : "text");
});
bindCheckbox("highlight_active", function(checked) {
env.editor.setHighlightActiveLine(checked);
});
bindCheckbox("show_hidden", function(checked) {
env.editor.setShowInvisibles(checked);
});
bindCheckbox("show_gutter", function(checked) {
env.editor.renderer.setShowGutter(checked);
});
bindCheckbox("show_print_margin", function(checked) {
env.editor.renderer.setShowPrintMargin(checked);
});
function bindCheckbox(id, callback) {
var el = document.getElementById(id);
var onCheck = function() {
callback(!!el.checked);
};
el.onclick = onCheck;
onCheck();
}
function bindDropdown(id, callback) {
var el = document.getElementById(id);
var onChange = function() {
callback(el.value);
};
el.onchange = onChange;
onChange();
}
function onResize() {
container.style.width = (document.documentElement.clientWidth - 4) + "px";
container.style.height = (document.documentElement.clientHeight - 55 - 4 - 23) + "px";
container.style.width = (document.documentElement.clientWidth) + "px";
container.style.height = (document.documentElement.clientHeight - 60 - 22) + "px";
env.editor.resize();
};
@ -277,16 +283,8 @@ exports.launch = function(env) {
return event.preventDefault(e);
});
// gutter
editor = env.editor
toggleGutter=function(){
editor.renderer.setShowGutter(!editor.renderer.showGutter)
}
//
window.ace={
editor: editor
}
window.env = env;
};
});

View file

@ -1,4 +1,4 @@
html {
html {
height: 100%;
overflow: hidden;
}
@ -15,24 +15,15 @@ body {
color: white;
}
#editor {
top: 55px;
#editor {
position: absolute;
top: 60px;
left: 0px;
background: white;
}
#controls {
width: 100%;
height: 55px;
}
#jump {
position: absolute;
width: 10px;
height: 10px;
border: 1px solid red;
z-index: 10000;
display: none;
}
#cockpitInput {
@ -53,20 +44,4 @@ body {
-moz-border-radius-topright: 10px;
border-top-left-radius: 4px; border-top-right-radius: 4px;
background: #DDD; color: #000;
}
#toggleGutter{
height:8px;
width:20px;
background:lightblue;
bottom:0;
position:absolute;
z-index: 1000;
-moz-border-radius-topright: 20px;
}
#toggleGutter:hover{
-moz-box-shadow: 2px -1px 5px 3px #91B6D5;
border-right: 1px solid #A1A1CF;
border-top: 1px solid #A1A1CF;
}

View file

@ -9,11 +9,9 @@
<link rel="stylesheet" href="demo/styles.css" type="text/css" media="screen" charset="utf-8">
</head>
<body>
<div id="jump"></div>
<table id="controls">
<tr>
<td>
<td align="right">
<label for="doc">Document:</label>
<select id="doc" size="1">
<option value="js">JS Document</option>
@ -21,9 +19,50 @@
<option value="css">CSS Document</option>
<option value="python">Python Document</option>
<option value="php">PHP Document</option>
<option value="plain">Text Document</option>
</select>
</td>
<td>
<td align="right">
<label for="theme">Theme:</label>
<select id="theme" size="1">
<option value="ace/theme/textmate">TextMate</option>
<option value="ace/theme/eclipse">Eclipse</option>
<option value="ace/theme/dawn">Dawn</option>
<option value="ace/theme/idle_fingers">idleFingers</option>
<option value="ace/theme/pastel_on_dark">Pastel on dark</option>
<option value="ace/theme/twilight">Twilight</option>
</select>
</td>
<td align="right">
<label for="fontsize">Font Size:</label>
<select id="fontsize" size="1">
<option value="10px">10px</option>
<option value="11px">11px</option>
<option value="12px" selected="selected">12px</option>
<option value="14px">14px</option>
<option value="16px">16px</option>
<option value="20px">20px</option>
<option value="24px">24px</option>
</select>
</td>
<td align="right">
<label for="select_style">Full Line Selection</label>
<input type="checkbox" name="select_style" id="select_style" checked>
</td>
<td align="right">
<label for="highlight_active">Highlight Active Line</label>
<input type="checkbox" name="highlight_active" id="highlight_active" checked>
</td>
<td align="right">
<label for="show_hidden">Show Invisibles</label>
<input type="checkbox" name="show_hidden" id="show_hidden">
</td>
<td align="right" rowspan="2">
<img src="demo/logo.png">
</td>
</tr>
<tr>
<td align="right">
<label for="mode">Mode:</label>
<select id="mode" size="1">
<option value="text">Plain Text</option>
@ -35,45 +74,44 @@
<option value="php">PHP</option>
</select>
</td>
<td>
<label for="theme">Theme:</label>
<select id="theme" size="1">
<option value="ace/theme/textmate">TextMate</option>
<option value="ace/theme/eclipse">Eclipse</option>
<option value="ace/theme/dawn">Dawn</option>
<option value="ace/theme/idle_fingers">idleFingers</option>
<option value="ace/theme/pastel_on_dark">Pastel on dark</option>
<option value="ace/theme/twilight">Twilight</option>
<td align="right">
<label for="keybinding">Key Binding:</label>
<select id="keybinding" size="1">
<option value="ace">Ace</option>
<option value="vim">Vim</option>
<option value="emacs">Emacs</option>
<option value="custom">Custom</option>
</select>
</td>
<td>
<label for="select_style">Full line selections</label>
<input type="checkbox" name="select_style" id="select_style" checked>
</td>
<td>
<label for="highlight_active">Highlight active line</label>
<input type="checkbox" name="highlight_active" id="highlight_active" checked>
</td>
<td>
<label for="show_hidden">Show invisibles</label>
<input type="checkbox" name="show_hidden" id="show_hidden">
<td align="right">
<label for="soft_wrap">Soft Wrap:</label>
<select id="soft_wrap" size="1">
<option value="off">Off</option>
<option value="40">40 Chars</option>
<option value="80">80 Chars</option>
</select>
</td>
<td align="right">
<img src="demo/logo.png">
<label for="show_gutter">Show Gutter</label>
<input type="checkbox" id="show_gutter" checked>
</td>
<td align="right">
<label for="show_print_margin">Show Print Margin</label>
<input type="checkbox" id="show_print_margin" checked>
</td>
</tr>
</table>
<div id="editor">
<div id="toggleGutter" onclick='toggleGutter()'></div>
</div>
<script type="text/editor" id="jstext">function foo(items) {
for (var i=0; i<items.length; i++) {
alert(items[i] + "juhu");
alert(items[i] + "juhu");
}
}</script>
}
// A magic character: >> ぁ <<
</script>
<script type="text/editor" id="csstext">.text-layer {
font-family: Monaco, "Courier New", monospace;
@ -99,7 +137,7 @@
</html></script>
<script type="text/editor" id="pythontext">#!/usr/local/bin/python
import string, sys
# If no arguments were given, print a helpful message
@ -109,7 +147,7 @@ if len(sys.argv)==1:
# Loop over the arguments
for i in sys.argv[1:]:
try:
try:
fahrenheit=float(string.atoi(i))
except string.atoi_error:
print repr(i), "not a numeric value"
@ -143,5 +181,17 @@ echo $output;
<script src="demo/require.js" type="text/javascript" charset="utf-8"></script>
<script src="demo/boot.js" type="text/javascript"></script>
<script type="text/editor" id="plaintext">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.
At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur
</script>
</body>
</html>

View file

@ -73,6 +73,18 @@
height: 100%;
}
.ace_editor textarea {
position: "absolute";
z-index: -1;
opacity: 0;
width: 10px;
height: 30px;
border: none;
resize: none;
outline: none;
overflow: hidden;
}
.ace_layer {
z-index: 1;
position: absolute;

View file

@ -64,9 +64,9 @@ var Document = function(text) {
this.getValue = function() {
return this.$lines.join(this.getNewLineCharacter());
};
// check for IE split bug
if ("aaa".split(/a/).length == 0)
if ("aaa".split(/a/).length == 0)
this.$split = function(text) {
return text.replace(/\r\n|\r/g, "\n").split("\n");
}
@ -75,7 +75,7 @@ var Document = function(text) {
return text.split(/\r\n|\r|\n/);
};
this.$detectNewLine = function(text) {
var match = text.match(/^.*?(\r?\n)/m);
if (match) {
@ -84,7 +84,7 @@ var Document = function(text) {
this.$autoNewLine = "\n";
}
};
this.getNewLineCharacter = function() {
switch (this.$newLineMode) {
case "windows":
@ -109,24 +109,24 @@ var Document = function(text) {
this.getNewLineMode = function() {
return this.$newLineMode;
};
this.isNewLine = function(text) {
return (text == "\r\n" || text == "\r" || text == "\n");
};
/**
* Get a verbatim copy of the given line as it is in the document
* Get a verbatim copy of the given line as it is in the document
*/
this.getLine = function(row) {
return this.$lines[row] || "";
};
this.getLines = function(firstRow, lastRow) {
return this.$lines.slice(firstRow, lastRow+1);
};
/**
* Returns all lines in the document as string array. Warning: The caller
* Returns all lines in the document as string array. Warning: The caller
* should not modify this array!
*/
this.getAllLines = function() {
@ -157,15 +157,15 @@ var Document = function(text) {
position.row = Math.max(0, length - 1);
position.column = this.getLine(length-1).length;
}
return position;
return position;
}
this.insert = function(position, text) {
if (text.length == 0)
return position;
position = this.$clipPosition(position);
if (this.getLength() <= 1)
this.$detectNewLine(text);
@ -182,56 +182,56 @@ var Document = function(text) {
this.insertNewLine(end);
if (newLines.length > 2)
this.insertLines(position.row+1, newLines.slice(1, newLines.length-1));
var end = this.insertInLine({row: position.row + newLines.length - 1, column: 0}, newLines[newLines.length-1]);
}
return end;
};
this.insertLines = function(row, lines) {
if (lines.length == 0)
return {row: row, column: 0};
var args = [row, 0];
args.push.apply(args, lines);
this.$lines.splice.apply(this.$lines, args);
var range = new Range(row, 0, row + lines.length - 1, 0);
var delta = {
action: "insertLines",
range: range,
lines: lines
};
this._dispatchEvent("change", { data: delta });
this._dispatchEvent("change", { data: delta });
return range.end;
},
this.insertNewLine = function(position) {
position = this.$clipPosition(position);
var line = this.$lines[position.row] || "";
this.$lines[position.row] = line.substring(0, position.column);
this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
var end = {
row : position.row + 1,
column : 0
};
var delta = {
action: "insertText",
range: Range.fromPoints(position, end),
text: this.getNewLineCharacter()
};
this._dispatchEvent("change", { data: delta });
return end;
};
this.insertInLine = function(position, text) {
if (text.length == 0)
return position;
var line = this.$lines[position.row] || "";
this.$lines[position.row] = line.substring(0, position.column) + text
+ line.substring(position.column);
@ -240,14 +240,14 @@ var Document = function(text) {
row : position.row,
column : position.column + text.length
};
var delta = {
action: "insertText",
range: Range.fromPoints(position, end),
text: text
};
this._dispatchEvent("change", { data: delta });
return end;
};
@ -258,12 +258,12 @@ var Document = function(text) {
if (range.isEmpty())
return range.start;
var firstRow = range.start.row;
var lastRow = range.end.row;
if (range.isMultiLine()) {
// TODO removeInLine can be optimized away!
this.removeInLine(lastRow, 0, range.end.column);
if (lastRow - firstRow >= 2)
@ -276,17 +276,17 @@ var Document = function(text) {
}
return range.start;
};
this.removeInLine = function(row, startColumn, endColumn) {
if (startColumn == endColumn)
return;
var range = new Range(row, startColumn, row, endColumn);
var line = this.getLine(row);
var removed = line.substring(startColumn, endColumn);
var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
this.$lines.splice(row, 1, newLine);
var delta = {
action: "removeText",
range: range,
@ -295,18 +295,18 @@ var Document = function(text) {
this._dispatchEvent("change", { data: delta });
return range.start;
};
/**
* Removes a range of full lines
*
*
* @param firstRow {Integer} The first row to be removed
* @param lastRow {Integer} The last row to be removed
* @return {String[]} The removed lines
*/
this.removeLines = function(firstRow, lastRow) {
var range = new Range(firstRow, 0, lastRow, this.$lines[lastRow].length);
var range = new Range(firstRow, 0, lastRow, this.$lines[lastRow].length);
var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
var delta = {
action: "removeLines",
range: range,
@ -316,16 +316,16 @@ var Document = function(text) {
this._dispatchEvent("change", { data: delta });
return removed;
};
this.removeNewLine = function(row) {
var firstLine = this.getLine(row);
var secondLine = this.getLine(row+1);
var range = new Range(row, firstLine.length, row+1, 0);
var line = firstLine + secondLine;
this.$lines.splice(row, 2, line);
var delta = {
action: "removeText",
range: range,
@ -333,16 +333,16 @@ var Document = function(text) {
};
this._dispatchEvent("change", { data: delta });
};
this.replace = function(range, text) {
if (text.length == 0 && range.isEmpty())
return range.start;
// Shortcut: If the text we want to insert is the same as it is already
// in the document, we don't have to replace anything.
if (text == this.getTextRange(range))
return range.end;
this.remove(range);
if (text) {
var end = this.insert(range.start, text);
@ -350,15 +350,15 @@ var Document = function(text) {
else {
end = range.start;
}
return end;
};
this.applyDeltas = function(deltas) {
for (var i=0; i<deltas.length; i++) {
var delta = deltas[i];
var range = Range.fromPoints(delta.range.start, delta.range.end);
if (delta.action == "insertLines")
this.insertLines(range.start.row, delta.lines)
else if (delta.action == "insertText")
@ -367,14 +367,14 @@ var Document = function(text) {
this.removeLines(range.start.row, range.end.row)
else if (delta.action == "removeText")
this.remove(range)
}
}
};
this.revertDeltas = function(deltas) {
for (var i=deltas.length-1; i>=0; i--) {
var delta = deltas[i];
var range = Range.fromPoints(delta.range.start, delta.range.end);
if (delta.action == "insertLines")
this.removeLines(range.start.row, range.end.row)
else if (delta.action == "insertText")
@ -383,7 +383,7 @@ var Document = function(text) {
this.insertLines(range.start.row, delta.lines)
else if (delta.action == "removeText")
this.insert(range.start, delta.text)
}
}
};
}).call(Document.prototype);

View file

@ -51,13 +51,14 @@ var EditSession = function(text, mode) {
this.$modified = true;
this.selection = new Selection(this);
this.$breakpoints = [];
this.$wrapData = [];
if (text instanceof Document) {
this.setDocument(text)
} else {
this.setDocument(new Document(text));
}
if (mode)
this.setMode(mode);
};
@ -70,15 +71,15 @@ var EditSession = function(text, mode) {
this.setDocument = function(doc) {
if (this.doc)
throw new Error("Document is already set");
this.doc = doc;
doc.on("change", this.onChange.bind(this));
};
this.getDocument = function() {
return this.doc;
};
this.onChange = function(e) {
var delta = e.data;
this.$modified = true;
@ -86,6 +87,8 @@ var EditSession = function(text, mode) {
this.$deltas.push(delta);
this.$informUndoManager.schedule();
}
this.$updateWrapDataOnChange(e);
this._dispatchEvent("change", e);
};
@ -98,7 +101,7 @@ var EditSession = function(text, mode) {
this.toString = function() {
return this.doc.getValue();
};
this.getSelection = function() {
return this.selection;
};
@ -164,7 +167,7 @@ var EditSession = function(text, mode) {
this.getTabSize = function() {
return this.$tabSize;
};
this.isTabStop = function(position) {
return this.$useSoftTabs && (position.column % this.$tabSize == 0);
};
@ -201,7 +204,7 @@ var EditSession = function(text, mode) {
};
/**
* Error:
* Error:
* {
* row: 12,
* column: 2, //can be undefined
@ -225,7 +228,7 @@ var EditSession = function(text, mode) {
this.getAnnotations = function() {
return this.$annotations;
};
this.clearAnnotations = function() {
this.$annotations = [];
this._dispatchEvent("changeAnnotation", {});
@ -239,12 +242,12 @@ var EditSession = function(text, mode) {
this.$autoNewLine = "\n";
}
};
this.tokenRe = /^[\w\d]+/g;
this.nonTokenRe = /^(?:[^\w\d|[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF])+/g
this.getWordRange = function(row, column) {
var line = this.getLine(row);
var inToken = false;
if (column > 0) {
inToken = !!line.charAt(column - 1).match(this.tokenRe);
@ -287,7 +290,7 @@ var EditSession = function(text, mode) {
if (this.$worker)
this.$worker.terminate();
if (window.Worker)
this.$worker = mode.createWorker(this);
@ -324,8 +327,8 @@ var EditSession = function(text, mode) {
return this.screenWidth;
};
this.$computeWidth = function() {
if (this.$modified) {
this.$computeWidth = function(force) {
if (this.$modified || force) {
this.$modified = false;
var lines = this.doc.getAllLines();
@ -344,17 +347,22 @@ var EditSession = function(text, mode) {
longestScreenLine = Math.max(longestScreenLine, len);
}
this.width = longestLine;
this.screenWidth = longestScreenLine;
if (this.$useWrapMode) {
this.screenWidth = this.$wrapLimit;
} else {
this.screenWidth = longestScreenLine;
}
}
};
/**
* Get a verbatim copy of the given line as it is in the document
* Get a verbatim copy of the given line as it is in the document
*/
this.getLine = function(row) {
return this.doc.getLine(row);
};
/**
* Get a line as it is displayed on screen. Tabs are replaced by spaces.
*/
@ -470,16 +478,16 @@ var EditSession = function(text, mode) {
this.insert = function(position, text) {
return this.doc.insert(position, text);
};
/**
* @param rows Array[Integer] sorted list of rows
*/
this.multiRowInsert = function(rows, column, text) {
this.multiRowInsert = function(rows, column, text) {
for (var i=rows.length-1; i>=0; i--) {
var row = rows[i];
if (row >= this.doc.getLength())
continue;
var diff = column - this.doc.getLine(row).length;
if ( diff > 0) {
var padded = lang.stringRepeat(" ", diff) + text;
@ -489,10 +497,10 @@ var EditSession = function(text, mode) {
padded = text;
offset = 0;
}
var end = this.insert({row: row, column: column+offset}, padded);
}
return {
rows: end ? end.row - rows[0] : 0,
columns: end ? end.column - column : 0
@ -506,29 +514,29 @@ var EditSession = function(text, mode) {
this.multiRowRemove = function(rows, range) {
if (range.start.row !== rows[0])
throw new TypeError("range must start in the first row!");
var height = range.end.row - rows[0];
for (var i=rows.length-1; i>=0; i--) {
var row = rows[i];
if (row >= this.doc.getLength())
continue;
var end = this.remove(new Range(row, range.start.column, row+height, range.end.column));
}
};
this.undoChanges = function(deltas) {
if (!deltas.length)
return;
this.$fromUndo = true;
this.doc.revertDeltas(deltas);
this.$fromUndo = false;
// update the selection
var firstDelta = deltas[0];
var lastDelta = deltas[deltas.length-1];
this.selection.clearSelection();
if (firstDelta.action == "insertText" || firstDelta.action == "insertLines")
this.selection.moveCursorToPosition(firstDelta.range.start);
@ -539,15 +547,15 @@ var EditSession = function(text, mode) {
this.redoChanges = function(deltas) {
if (!deltas.length)
return;
this.$fromUndo = true;
this.doc.applyDeltas(deltas);
this.$fromUndo = false;
// update the selection
var firstDelta = deltas[0];
var lastDelta = deltas[deltas.length-1];
this.selection.clearSelection();
if (firstDelta.action == "insertText" || firstDelta.action == "insertLines")
this.selection.setSelectionRange(Range.fromPoints(firstDelta.range.start, lastDelta.range.end));
@ -571,15 +579,15 @@ var EditSession = function(text, mode) {
var rowRange = range.collapseRows();
var deleteRange = new Range(0, 0, 0, 0);
var size = this.getTabSize();
for (var i = rowRange.start.row; i <= rowRange.end.row; ++i) {
var line = this.getLine(i);
deleteRange.start.row = i;
deleteRange.end.row = i;
for (var j = 0; j < size; ++j)
if (line.charAt(j) != ' ')
break;
break;
if (j < size && line.charAt(j) == '\t') {
deleteRange.start.column = j;
deleteRange.end.column = j + 1;
@ -594,7 +602,7 @@ var EditSession = function(text, mode) {
this.remove(deleteRange);
}
return range;
}
}
this.moveLinesUp = function(firstRow, lastRow) {
if (firstRow <= 0) return 0;
@ -627,87 +635,499 @@ var EditSession = function(text, mode) {
return Math.max(0, Math.min(row, this.doc.getLength()-1));
};
this.documentToScreenColumn = function(row, docColumn) {
// WRAPMODE
this.$wrapLimit = 80;
this.$useWrapMode = false;
this.setUseWrapMode = function(useWrapMode) {
if (useWrapMode != this.$useWrapMode) {
this.$useWrapMode = useWrapMode;
this.$updateWrapData(0, this.getLength() - 1);
this.$modified = true;
this._dispatchEvent("changeWrapMode");
}
};
this.getUseWrapMode = function() {
return this.$useWrapMode;
};
this.setWrapLimit = function(wrapLimit) {
if (wrapLimit != this.$wrapLimit) {
this.$wrapLimit = wrapLimit;
this.$updateWrapData(0, this.getLength() - 1);
this._dispatchEvent("changeWrapMode");
}
};
this.getWrapLimit = function() {
return this.$wrapLimit;
};
this.$updateWrapDataOnChange = function(e) {
if (!this.$useWrapMode) {
return;
}
var action = e.data.action;
var firstRow = e.data.range.start.row,
lastRow = e.data.range.end.row;
if (action.indexOf("Lines") != -1) {
if (action == "insertLines") {
lastRow = firstRow + e.data.lines.length;
} else {
firstRow = lastRow - e.data.lines.length;
}
}
if (firstRow != lastRow) {
var len = lastRow - firstRow;
if (action.indexOf("remove") != -1) {
this.$wrapData.splice(firstRow, len);
lastRow = firstRow;
} else {
var args = [firstRow, 0];
for (var i = 0; i < len; i++) args.push([]);
this.$wrapData.splice.apply(this.$wrapData, args);
}
}
this.$updateWrapData(firstRow, lastRow);
};
this.$updateWrapData = function(firstRow, lastRow) {
var lines = this.doc.getAllLines();
var tabSize = this.getTabSize();
var wrapData = this.$wrapData;
var wrapLimit = this.$wrapLimit;
// Remove lines that are no longer there.
wrapData.splice(lines.length, wrapData.length - lines.length);
for (var row = firstRow; row <= lastRow; row++) {
wrapData[row] =
this.$computeWrapSplits(lines[row], wrapLimit, tabSize);
}
};
// "Tokens"
var CHAR = 1,
CHAR_EXT = 2,
SPACE = 3,
TAB = 4,
TAB_SPACE = 5;
this.$computeWrapSplits = function(textLine, wrapLimit, tabSize) {
textLine = textLine.trimRight();
if (textLine.length == 0) {
return [];
}
var tabSize = this.getTabSize();
var splits = [];
var tokens = this.$getDisplayTokens(textLine);
var displayLength = tokens.length;
var lastSplit = 0, lastDocSplit = 0;
function addSplit(screenPos) {
var displayed = tokens.slice(lastSplit, screenPos);
// The document size is the current size - the extra width for tabs
// and multipleWidth characters.
var len = displayed.length;
displayed.join("").
// Get all the tabs.
replace(/4/g, function(m) {
len -= tabSize - 1;
}).
// Get all the multipleWidth characters.
replace(/2/g, function(m) {
len -= 1;
});
lastDocSplit += len;
splits.push(lastDocSplit);
lastSplit = screenPos;
}
while (displayLength - lastSplit > wrapLimit) {
// This is, where the split should be.
var split = lastSplit + wrapLimit;
// If there is a space or tab at this split position.
if (tokens[split] >= SPACE) {
// Include all following spaces + tabs in this split as well.
while (tokens[split] >= SPACE) {
split ++;
}
addSplit(split);
} else {
// Search for the first non space/tab token.
for (split; split != lastSplit - 1; split--) {
if (tokens[split] >= SPACE) {
split++;
break;
}
}
// If we found one, then add the split.
if (split > lastSplit) {
addSplit(split);
}
// No space or tab around? Well, force a split then.
else {
addSplit(lastSplit + wrapLimit);
}
}
}
return splits;
}
this.$getDisplayTokens = function(str) {
var arr = [];
var tabSize = this.getTabSize();
for (var i = 0; i < str.length; i++) {
var c = str.charCodeAt(i);
// Tab
if (c == 9) {
arr.push(TAB);
for (var n = 1; n < tabSize; n++) {
arr.push(TAB_SPACE);
}
}
// Space
else if(c == 32) {
arr.push(SPACE);
}
// CJK characters
else if (
c >= 0x3040 && c <= 0x309F || // Hiragana
c >= 0x30A0 && c <= 0x30FF || // Katakana
c >= 0x4E00 && c <= 0x9FFF || // Single CJK ideographs
c >= 0xF900 && c <= 0xFAFF ||
c >= 0x3400 && c <= 0x4DBF
) {
arr.push(CHAR, CHAR_EXT);
} else {
arr.push(CHAR);
}
}
return arr;
}
/**
* Calculates the width of the a string on the screen while assuming that
* the string starts at the first column on the screen.
*
* @param string str String to calculate the screen width of
* @return int number of columns for str on screen.
*/
this.$getStringScreenWidth = function(str) {
var screenColumn = 0;
var remaining = docColumn;
var line = this.getLine(row);
var tabSize = this.getTabSize();
for (var i=0; i<line.length; i++) {
var c = line.charCodeAt(i);
if (remaining > 0) {
remaining -= 1;
// tab
if (c == 9) {
screenColumn += tabSize;
}
// CJK characters
for (var i=0; i<str.length; i++) {
var c = str.charCodeAt(i);
// tab
if (c == 9) {
screenColumn += tabSize;
}
// CJK characters
else if (
c >= 0x3040 && c <= 0x309F || // Hiragana
c >= 0x30A0 && c <= 0x30FF || // Katakana
c >= 0x4E00 && c <= 0x9FFF || // Single CJK ideographs
c >= 0xF900 && c <= 0xFAFF ||
c >= 0x3400 && c <= 0x4DBF
) {
screenColumn += 2;
} else {
screenColumn += 1;
}
}
return screenColumn;
}
this.getRowHeight = function(config, row) {
var rows;
if (!this.$useWrapMode) {
rows = 1;
} else {
rows = this.$wrapData[row].length + 1;
}
return rows * config.lineHeight;
}
this.getScreenLastRowColumn = function(screenRow, returnDocPosition) {
if (!this.$useWrapMode) {
return this.$getStringScreenWidth(this.getLine(screenRow));
}
var rowData = this.$screenToDocumentRow(screenRow);
var docRow = rowData[0],
row = rowData[1];
var start, end;
if (this.$wrapData[docRow][row]) {
start = (this.$wrapData[docRow][row - 1] || 0);
end = this.$wrapData[docRow][row];
returnDocPosition && end--;
} else {
end = this.getLine(docRow).length;
start = (this.$wrapData[docRow][row - 1] || 0);
}
if (!returnDocPosition) {
return this.$getStringScreenWidth(this.getLine(docRow).substring(start, end));
} else {
return end;
}
};
this.getDocumentLastRowColumn = function(docRow, docColumn) {
if (!this.$useWrapMode) {
return this.getLine(docRow).length;
}
var screenRow = this.documentToScreenRow(docRow, docColumn);
return this.getScreenLastRowColumn(screenRow, true);
}
this.getScreenFirstRowColumn = function(screenRow) {
if (!this.$useWrapMode) {
return 0;
}
var rowData = this.$screenToDocumentRow(screenRow);
var docRow = rowData[0],
row = rowData[1];
return this.$wrapData[docRow][row - 1] || 0;
};
this.getRowSplitData = function(row) {
if (!this.$useWrapMode) {
return undefined;
} else {
return this.$wrapData[row];
}
};
/**
*
* @returns array
* - array[0]: The documentRow aquivalent.
* - array[1]: The screenRowOffset to the first documentRow on the screen.
*/
this.$screenToDocumentRow = function(row) {
if (!this.$useWrapMode) {
return [row, 0];
}
var wrapData = this.$wrapData, linesCount = this.getLength();
var docRow = 0;
while (docRow < linesCount && row >= wrapData[docRow].length + 1) {
row -= wrapData[docRow].length + 1;
docRow ++;
}
return [docRow, row];
};
this.screenToDocumentRow = function(screenRow) {
return this.$screenToDocumentRow(screenRow)[0];
};
this.screenToDocumentColumn = function(screenRow, screenColumn) {
return this.screenToDocumentPosition(screenRow, screenColumn).column;
};
this.screenToDocumentPosition = function(row, column) {
var line;
var docRow;
var docColumn;
var remaining = column;
if (!this.$useWrapMode) {
docRow = row;
row = 0;
docColumn = 0;
line = this.getLine(docRow);
} else {
var wrapData = this.$wrapData, linesCount = this.getLength();
var rowData = this.$screenToDocumentRow(row);
row = rowData[1];
docRow = rowData[0];
if (docRow >= linesCount) {
return {
row: docRow,
column: 0
};
}
docColumn = wrapData[docRow][row - 1] || 0;
line = this.getLine(docRow).substring(docColumn);
}
var tabSize = this.getTabSize();
for(var i = 0; i < line.length; i++) {
var c = line.charCodeAt(i);
if (remaining > 0) {
docColumn += 1;
// tab
if (c == 9) {
if (remaining >= tabSize) {
remaining -= tabSize;
} else {
remaining = 0;
docColumn -= 1;
}
}
// CJK characters
else if (
c >= 0x3040 && c <= 0x309F || // Hiragana
c >= 0x30A0 && c <= 0x30FF || // Katakana
c >= 0x4E00 && c <= 0x9FFF || // Single CJK ideographs
c >= 0xF900 && c <= 0xFAFF ||
c >= 0x3400 && c <= 0x4DBF
) {
screenColumn += 2;
} else {
screenColumn += 1;
}
} else {
break;
}
}
return screenColumn;
};
this.screenToDocumentColumn = function(row, screenColumn) {
var tabSize = this.getTabSize();
var docColumn = 0;
var remaining = screenColumn;
var line = this.getLine(row);
for(var i=0; i<line.length; i++) {
var c = line.charCodeAt(i);
if (remaining > 0) {
docColumn += 1;
// tab
if (c == 9) {
if (remaining >= tabSize) {
remaining -= tabSize;
} else {
remaining = 0;
docColumn -= 1;
}
}
// CJK characters
else if (
c >= 0x3040 && c <= 0x309F || // Hiragana
c >= 0x30A0 && c <= 0x30FF || // Katakana
c >= 0x4E00 && c <= 0x9FFF || // Single CJK ideographs
c >= 0xF900 && c <= 0xFAFF ||
c >= 0xF900 && c <= 0xFAFF ||
c >= 0x3400 && c <= 0x4DBF
) {
if (remaining >= 2) {
remaining -= 2;
} else {
remaining = 0;
docColumn -= 1;
}
} else {
remaining -= 1;
}
} else {
break;
}
}
return docColumn;
remaining -= 2;
} else {
remaining = 0;
docColumn -= 1;
}
} else {
remaining -= 1;
}
} else {
break;
}
}
// Clamp docColumn.
if (docRow < linesCount && wrapData[docRow][row]) {
if (docColumn >= wrapData[docRow][row]) {
// We remove one character at the end such that the docColumn
// position returned is not associated to the next row on the
// screen.
docColumn = wrapData[docRow][row] - 1;
}
} else if (this.getLine(docRow)) {
docColumn = Math.min(docColumn, this.getLine(docRow).length);
}
return {
row: docRow,
column: docColumn
};
};
this.documentToScreenColumn = function(row, docColumn) {
return this.documentToScreenPosition(row, docColumn).column;
};
/**
*
* @return array[2]
* - array[0]: The number of the row on the screen (aka screenRow)
* - array[1]: The number of rows from the first docRow on the screen
* (aka screenRowOffset);
*/
this.$documentToScreenRow = function(docRow, docColumn) {
if (!this.$useWrapMode) {
return [docRow, 0];
}
var wrapData = this.$wrapData;
var screenRow = 0;
// Handle special case where the row is outside of the range of lines.
if (docRow > wrapData.length - 1) {
return [
this.getScreenLength(),
wrapData[wrapData.length - 1].length - 1
];
}
for (var i = 0; i < docRow; i++) {
screenRow += wrapData[i].length + 1;
}
var screenRowOffset = 0;
while (docColumn >= wrapData[docRow][screenRowOffset]) {
screenRow ++;
screenRowOffset++;
}
return [screenRow, screenRowOffset];
}
this.documentToScreenRow = function(docRow, docColumn) {
return this.$documentToScreenRow(docRow, docColumn)[0];
}
this.documentToScreenPosition = function(pos, column) {
var str;
var tabSize = this.getTabSize();
// Normalize the passed in arguments.
var row;
if (column != null) {
row = pos;
} else {
row = pos.row;
column = pos.column;
}
if (!this.$useWrapMode) {
str = this.getLine(row).substring(0, column);
column = this.$getStringScreenWidth(str);
return {
row: row,
column: column
};
}
if (row >= this.getLength()) {
return {
row: screenRow,
column: 0
};
}
var split;
var wrapRowData = this.$wrapData[row];
var screenRow, screenRowOffset;
var screenColumn;
var rowData = this.$documentToScreenRow(row, column);
screenRow = rowData[0];
screenRowOffset = rowData[1];
str = this.getLine(row).substring(
wrapRowData[screenRowOffset - 1] || 0, column);
screenColumn = this.$getStringScreenWidth(str);
return {
row: screenRow,
column: screenColumn
};
};
this.getScreenLength = function() {
if (!this.$useWrapMode) {
return this.getLength();
}
var screenRows = 0;
for (var row = 0; row < this.$wrapData.length; row++) {
screenRows += this.$wrapData[row].length + 1;
}
return screenRows;
}
}).call(EditSession.prototype);
exports.EditSession = EditSession;

View file

@ -22,6 +22,7 @@
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -55,7 +56,7 @@ var Editor =function(renderer, session) {
this.container = container;
this.renderer = renderer;
this.textInput = new TextInput(container, this);
this.textInput = new TextInput(renderer.getTextAreaContainer(), this);
this.keyBinding = new KeyBinding(this);
var self = this;
event.addListener(container, "mousedown", function(e) {
@ -128,6 +129,7 @@ var Editor =function(renderer, session) {
this.session.removeEventListener("change", this.$onDocumentChange);
this.session.removeEventListener("changeMode", this.$onDocumentModeChange);
this.session.removeEventListener("changeTabSize", this.$onDocumentChangeTabSize);
this.session.removeEventListener("changeWrapMode", this.$onDocumentChangeWrapMode);
this.session.removeEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
this.session.removeEventListener("changeAnnotation", this.$onDocumentChangeAnnotation);
@ -150,14 +152,16 @@ var Editor =function(renderer, session) {
this.$onDocumentChangeTabSize = this.renderer.updateText.bind(this.renderer);
session.addEventListener("changeTabSize", this.$onDocumentChangeTabSize);
this.$onDocumentChangeWrapMode = this.renderer.updateFull.bind(this.renderer);
session.addEventListener("changeWrapMode", this.$onDocumentChangeWrapMode);
this.$onDocumentChangeBreakpoint = this.onDocumentChangeBreakpoint.bind(this);
this.session.addEventListener("changeBreakpoint", this.$onDocumentChangeBreakpoint);
this.$onDocumentChangeAnnotation = this.onDocumentChangeAnnotation.bind(this);
this.session.addEventListener("changeAnnotation", this.$onDocumentChangeAnnotation);
this.selection = session.getSelection();
this.$desiredColumn = 0;
this.$onCursorChange = this.onCursorChange.bind(this);
this.selection.addEventListener("changeCursor", this.$onCursorChange);
@ -175,7 +179,7 @@ var Editor =function(renderer, session) {
this.onDocumentChangeAnnotation();
this.renderer.scrollToRow(session.getScrollTopRow());
this.renderer.updateFull();
this._dispatchEvent("changeSession", {
session: session,
oldSession: oldSession
@ -258,11 +262,11 @@ var Editor =function(renderer, session) {
this.onDocumentChange = function(e) {
var delta = e.data;
var range = delta.range;
this.bgTokenizer.start(range.start.row);
if (range.start.row == range.end.row)
var lastRow = range.end.row;
else
else
lastRow = Infinity;
this.renderer.updateLines(range.start.row, lastRow);
@ -277,6 +281,11 @@ var Editor =function(renderer, session) {
this.onCursorChange = function(e) {
this.$highlightBrackets();
// move text input over the cursor
// this is required for iOS and IME
this.renderer.moveTextAreaToCursor(this.textInput.getElement());
this.renderer.updateCursor(this.getCursorPosition(), this.$overwrite);
if (!this.$blockScrolling && (!e || !e.blockScrolling)) {
@ -414,13 +423,11 @@ var Editor =function(renderer, session) {
this.onMouseDoubleClick = function(e) {
this.selection.selectWord();
this.$clickSelection = this.getSelectionRange();
this.$updateDesiredColumn();
};
this.onMouseTripleClick = function(e) {
this.selection.selectLine();
this.$clickSelection = this.getSelectionRange();
this.$updateDesiredColumn();
};
this.onMouseWheel = function(e) {
@ -684,7 +691,6 @@ var Editor =function(renderer, session) {
var range = this.session.outdentRows(selection.getRange());
selection.setSelectionRange(range, selection.isBackwards());
this.$updateDesiredColumn();
};
this.toggleCommentLines = function() {
@ -874,17 +880,14 @@ var Editor =function(renderer, session) {
this.clearSelection = function() {
this.selection.clearSelection();
this.$updateDesiredColumn();
};
this.moveCursorTo = function(row, column) {
this.selection.moveCursorTo(row, column);
this.$updateDesiredColumn();
};
this.moveCursorToPosition = function(pos) {
this.selection.moveCursorToPosition(pos);
this.$updateDesiredColumn();
};
@ -903,34 +906,16 @@ var Editor =function(renderer, session) {
this.navigateTo = function(row, column) {
this.clearSelection();
this.moveCursorTo(row, column);
this.$updateDesiredColumn(column);
};
this.navigateUp = function(times) {
this.selection.clearSelection();
this.selection.moveCursorBy(-(times || 1), 0);
if (this.$desiredColumn) {
var cursor = this.getCursorPosition();
var column = this.session.screenToDocumentColumn(cursor.row, this.$desiredColumn);
this.selection.moveCursorTo(cursor.row, column);
}
this.selection.moveCursorBy(-1, 0);
};
this.navigateDown = function(times) {
this.selection.clearSelection();
this.selection.moveCursorBy(times || 1, 0);
if (this.$desiredColumn) {
var cursor = this.getCursorPosition();
var column = this.session.screenToDocumentColumn(cursor.row, this.$desiredColumn);
this.selection.moveCursorTo(cursor.row, column);
}
};
this.$updateDesiredColumn = function() {
var cursor = this.getCursorPosition();
this.$desiredColumn = this.session.documentToScreenColumn(cursor.row, cursor.column);
this.selection.moveCursorBy(1, 0);
};
this.navigateLeft = function(times) {
@ -999,7 +984,6 @@ var Editor =function(renderer, session) {
this.$tryReplace(range, replacement);
if (range !== null)
this.selection.setSelectionRange(range);
this.$updateDesiredColumn();
},
this.replaceAll = function(replacement, options) {
@ -1018,7 +1002,6 @@ var Editor =function(renderer, session) {
this.$tryReplace(ranges[i], replacement);
if (ranges[0] !== null)
this.selection.setSelectionRange(ranges[0]);
this.$updateDesiredColumn();
},
this.$tryReplace = function(range, replacement) {
@ -1071,7 +1054,6 @@ var Editor =function(renderer, session) {
var range = this.$search.find(this.session);
if (range) {
this.gotoLine(range.end.row+1, range.end.column);
this.$updateDesiredColumn();
this.selection.setSelectionRange(range);
}
};

View file

@ -197,7 +197,7 @@ StateHandler.prototype = {
// If we pressed any command key but no other key, then ignore the input.
// Otherwise "shift-" is added to the buffer, and later on "shift-g"
// which results in "shift-shift-g" which doesn't make senese.
if (hashId != 0 && (key == "" || String.fromCharCode(0))) {
if (hashId != 0 && (key == "" || key == String.fromCharCode(0))) {
return null;
}

View file

@ -38,39 +38,13 @@
define(function(require, exports, module) {
var event = require("pilot/event");
var useragent = require("pilot/useragent");
var TextInput = function(parentNode, host) {
var text = document.createElement("textarea");
var style = text.style;
style.position = "fixed";
style.left = "-10000px";
style.top = "-10000px";
parentNode.appendChild(text);
// move text input over the cursor
// this is required for iOS and IME
style.left = "0px";
style.top = "0px";
style.zIndex = -1;
style.opacity = 0;
style.width = "10px";
style.height = "30px";
var changeCursor = function() {
var cursor = host.getCursorPosition();
var pos = host.renderer.textToScreenCoordinates(cursor.row, cursor.column);
var epos = parentNode.getBoundingClientRect();
style.left = (pos.pageX - epos.left - 6) + "px";
style.top = (pos.pageY - epos.top + 52) + "px";
};
host.addEventListener("changeSession", function(e) {
if (e.oldSession)
e.oldSession.getSelection().removeEventListener("changeCursor", changeCursor);
e.session.getSelection().addEventListener("changeCursor", changeCursor);
});
var PLACEHOLDER = String.fromCharCode(0);
sendText();
@ -97,6 +71,7 @@ var TextInput = function(parentNode, host) {
}
var onTextInput = function(e) {
if (useragent.isIE && text.value.charCodeAt(0) > 128) return;
setTimeout(function() {
if (!inCompostion)
sendText();
@ -105,40 +80,62 @@ var TextInput = function(parentNode, host) {
var onCompositionStart = function(e) {
inCompostion = true;
sendText();
text.value = "";
if (!useragent.isIE) {
sendText();
text.value = "";
};
host.onCompositionStart();
setTimeout(onCompositionUpdate, 0);
if (!useragent.isGecko) setTimeout(onCompositionUpdate, 0);
};
var onCompositionUpdate = function() {
if (!inCompostion) return;
host.onCompositionUpdate(text.value);
};
var onCompositionEnd = function() {
inCompostion = false;
host.onCompositionEnd();
onTextInput();
setTimeout(function () {
sendText();
}, 0);
};
var onCopy = function() {
var onCopy = function(e) {
copied = true;
text.value = host.getCopyText();
var copyText = host.getCopyText();
if(copyText)
text.value = copyText;
else
e.preventDefault();
text.select();
copied = true;
setTimeout(sendText, 0);
};
var onCut = function() {
var onCut = function(e) {
copied = true;
text.value = host.getCopyText();
host.onCut();
var copyText = host.getCopyText();
if(copyText) {
text.value = copyText;
host.onCut();
} else
e.preventDefault();
text.select();
setTimeout(sendText, 0);
};
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
event.addListener(text, "keypress", onTextInput);
if (useragent.isIE) {
var keytable = { 13:1, 27:1 };
event.addListener(text, "keyup", function (e) {
if (inCompostion && (!text.value || keytable[e.keyCode])) setTimeout(onCompositionEnd, 0);
if ((text.value.charCodeAt(0)|0) < 129) {
return;
};
inCompostion ? onCompositionUpdate() : onCompositionStart();
});
};
event.addListener(text, "textInput", onTextInput);
event.addListener(text, "paste", function(e) {
// Some browsers support the event.clipboardData API. Use this to get
@ -153,13 +150,20 @@ var TextInput = function(parentNode, host) {
onTextInput();
}
});
event.addListener(text, "propertychange", onTextInput);
if (!useragent.isIE) {
event.addListener(text, "propertychange", onTextInput);
};
event.addListener(text, "copy", onCopy);
event.addListener(text, "cut", onCut);
event.addListener(text, "compositionstart", onCompositionStart);
event.addListener(text, "compositionupdate", onCompositionUpdate);
if (useragent.isGecko) {
event.addListener(text, "text", onCompositionUpdate);
};
if (useragent.isWebKit) {
event.addListener(text, "keyup", onCompositionUpdate);
};
event.addListener(text, "compositionend", onCompositionEnd);
event.addListener(text, "blur", function() {
@ -180,6 +184,10 @@ var TextInput = function(parentNode, host) {
this.blur = function() {
text.blur();
};
this.getElement = function() {
return text;
};
};
exports.TextInput = TextInput;

View file

@ -20,6 +20,7 @@
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -57,10 +58,9 @@ var Cursor = function(parentEl) {
};
this.setCursor = function(position, overwrite) {
this.position = {
row : position.row,
column : this.session.documentToScreenColumn(position.row, position.column)
};
this.position =
this.session.documentToScreenPosition(position);
if (overwrite) {
dom.addCssClass(this.cursor, "ace_overwrite");
} else {
@ -100,7 +100,7 @@ var Cursor = function(parentEl) {
}, 1000);
};
this.getPixelPosition = function() {
this.getPixelPosition = function(onScreen) {
if (!this.config || !this.position) {
return {
left : 0,
@ -108,10 +108,12 @@ var Cursor = function(parentEl) {
};
}
var cursorLeft = Math.round(this.position.column * this.config.characterWidth);
var cursorTop = this.position.row * this.config.lineHeight;
var pos = this.position;
var cursorLeft = Math.round(pos.column * this.config.characterWidth);
var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) *
this.config.lineHeight;
return {
return {
left : cursorLeft,
top : cursorTop
};
@ -123,17 +125,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(true);
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";

View file

@ -20,6 +20,7 @@
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -51,12 +52,16 @@ var Gutter = function(parentEl) {
(function() {
this.setSession = function(session) {
this.session = session;
};
this.addGutterDecoration = function(row, className){
if (!this.$decorations[row])
if (!this.$decorations[row])
this.$decorations[row] = "";
this.$decorations[row] += " ace_" + className;
}
this.removeGutterDecoration = function(row, className){
this.$decorations[row] = this.$decorations[row].replace(" ace_" + className, "");
};
@ -101,7 +106,7 @@ var Gutter = function(parentEl) {
this.$breakpoints[i] ? " ace_breakpoint " : " ",
annotation.className,
"' title='", annotation.text.join("\n"),
"' style='height:", config.lineHeight, "px;'>", (i+1), "</div>");
"' style='height:", this.session.getRowHeight(config, i), "px;'>", (i+1), "</div>");
html.push("</div>");
}
this.element = dom.setInnerHtml(this.element, html.join(""));

View file

@ -20,6 +20,7 @@
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -87,6 +88,8 @@ var Marker = function(parentEl) {
var range = marker.range.clipRows(config.firstRow, config.lastRow);
if (range.isEmpty()) continue;
range = range.toScreenRange(this.session);
if (range.isMultiLine()) {
if (marker.type == "text") {
this.drawTextMarker(html, range, marker.clazz, config);
@ -101,11 +104,16 @@ var Marker = function(parentEl) {
this.element = dom.setInnerHtml(this.element, html.join(""));
};
this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig) {
this.$getTop = function(row, layerConfig) {
return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight;
};
this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig) {
// selection start
var row = range.start.row;
var lineRange = new Range(row, range.start.column, row, this.session.getLine(row).length);
var lineRange = new Range(row, range.start.column,
row, this.session.getScreenLastRowColumn(row));
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1);
// selection end
@ -116,18 +124,16 @@ var Marker = function(parentEl) {
for (var row = range.start.row + 1; row < range.end.row; row++) {
lineRange.start.row = row;
lineRange.end.row = row;
lineRange.end.column = this.session.getLine(row).length; // account for endofline characters
lineRange.end.column = this.session.getScreenLastRowColumn(row);
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1);
}
};
this.drawMultiLineMarker = function(stringBuilder, range, clazz, layerConfig) {
var range = range.toScreenRange(this.session);
// from selection start to the end of the line
var height = layerConfig.lineHeight;
var width = Math.round(layerConfig.width - (range.start.column * layerConfig.characterWidth));
var top = (range.start.row - layerConfig.firstRow) * layerConfig.lineHeight;
var top = this.$getTop(range.start.row, layerConfig);
var left = Math.round(range.start.column * layerConfig.characterWidth);
stringBuilder.push(
@ -139,7 +145,7 @@ var Marker = function(parentEl) {
);
// from start of the last line to the selection end
var top = (range.end.row - layerConfig.firstRow) * layerConfig.lineHeight;
var top = this.$getTop(range.end.row, layerConfig);
var width = Math.round(range.end.column * layerConfig.characterWidth);
stringBuilder.push(
@ -153,7 +159,7 @@ var Marker = function(parentEl) {
var height = (range.end.row - range.start.row - 1) * layerConfig.lineHeight;
if (height < 0)
return;
var top = (range.start.row + 1 - layerConfig.firstRow) * layerConfig.lineHeight;
var top = this.$getTop(range.start.row + 1, layerConfig);
stringBuilder.push(
"<div class='", clazz, "' style='",
@ -164,11 +170,9 @@ var Marker = function(parentEl) {
};
this.drawSingleLineMarker = function(stringBuilder, range, clazz, layerConfig, extraLength) {
var range = range.toScreenRange(this.session);
var height = layerConfig.lineHeight;
var width = Math.round((range.end.column + (extraLength || 0) - range.start.column) * layerConfig.characterWidth);
var top = (range.start.row - layerConfig.firstRow) * layerConfig.lineHeight;
var top = this.$getTop(range.start.row, layerConfig);
var left = Math.round(range.start.column * layerConfig.characterWidth);
stringBuilder.push(

View file

@ -20,6 +20,7 @@
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -96,15 +97,15 @@ var Text = function(parentEl) {
if (!this.$measureNode) {
var measureNode = this.$measureNode = document.createElement("div");
var style = measureNode.style;
style.width = style.height = "auto";
style.left = style.top = "-1000px";
style.visibility = "hidden";
style.position = "absolute";
style.overflow = "visible";
style.whiteSpace = "nowrap";
// in FF 3.6 monospace fonts can have a fixed sub pixel width.
// that's why we have to measure many characters
// Note: characterWidth can be a float!
@ -133,7 +134,7 @@ var Text = function(parentEl) {
this.setShowInvisibles = function(showInvisibles) {
if (this.showInvisibles == showInvisibles)
return false;
this.showInvisibles = showInvisibles;
return true;
};
@ -152,23 +153,31 @@ var Text = function(parentEl) {
}
};
this.updateLines = function(layerConfig, firstRow, lastRow) {
this.updateLines = function(config, firstRow, lastRow) {
this.$computeTabString();
this.config = layerConfig;
var first = Math.max(firstRow, layerConfig.firstRow);
var last = Math.min(lastRow, layerConfig.lastRow);
// Due to wrap line changes there can be new lines if e.g.
// the line to updated wrapped in the meantime.
if (this.config.lastRow != config.lastRow ||
this.config.firstRow != config.firstRow) {
this.scrollLines(config);
}
this.config = config;
var first = Math.max(firstRow, config.firstRow);
var last = Math.min(lastRow, config.lastRow);
var lineElements = this.element.childNodes;
var tokens = this.tokenizer.getTokens(first, last);
for (var i=first; i<=last; i++) {
var lineElement = lineElements[i - layerConfig.firstRow];
var lineElement = lineElements[i - config.firstRow];
if (!lineElement)
continue;
var html = [];
this.$renderLine(html, i, tokens[i-first].tokens);
dom.setInnerHtml(lineElement, html.join(""));
lineElement = dom.setInnerHtml(lineElement, html.join(""));
lineElement.style.height =
this.session.getRowHeight(config, i) + "px";
}
};
@ -200,7 +209,7 @@ var Text = function(parentEl) {
else
el.appendChild(fragment);
}
if (config.lastRow > oldConfig.lastRow) {
var fragment = this.$renderLinesFragment(config, oldConfig.lastRow + 1, config.lastRow);
el.appendChild(fragment);
@ -214,7 +223,7 @@ var Text = function(parentEl) {
var lineEl = document.createElement("div");
lineEl.className = "ace_line";
var style = lineEl.style;
style.height = this.$characterSize.height + "px";
style.height = this.session.getRowHeight(config, row) + "px";
style.width = config.width + "px";
var html = [];
@ -231,14 +240,12 @@ var Text = function(parentEl) {
this.config = config;
var html = [];
var tokens = this.tokenizer.getTokens(config.firstRow, config.lastRow);
for (var i=config.firstRow; i<=config.lastRow; i++) {
html.push("<div class='ace_line' style='height:" + this.$characterSize.height + "px;", "width:",
config.width, "px'>");
this.$renderLine(html, i, tokens[i-config.firstRow].tokens), html.push("</div>");
}
var tokens = this.tokenizer.getTokens(config.firstRow, config.lastRow)
var fragment = this.$renderLinesFragment(config, config.firstRow, config.lastRow);
this.element = dom.setInnerHtml(this.element, html.join(""));
// Clear the current content of the element and add the rendered fragment.
this.element.innerHTML = "";
this.element.appendChild(fragment);
};
this.$textToken = {
@ -258,7 +265,7 @@ var Text = function(parentEl) {
var space = new Array(space.length+1).join(self.SPACE_CHAR);
return "<span class='ace_invisible'>" + space + "</span>";
}
};
}
else {
@ -266,27 +273,63 @@ var Text = function(parentEl) {
var spaceReplace = "&nbsp;";
}
var _self = this;
var characterWidth = this.config.characterWidth;
for ( var i = 0; i < tokens.length; i++) {
var token = tokens[i];
var output = token.value
function addToken(token, value) {
var output = value
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(spaceRe, spaceReplace)
.replace(/\t/g, this.$tabString)
.replace(/\t/g, _self.$tabString)
.replace(/[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF]/g, function(c) {
return "<span class='ace_cjk' style='width:" + (characterWidth * 2) + "px'>" + c + "</span>"
});
if (!this.$textToken[token.type]) {
if (!_self.$textToken[token.type]) {
var classes = "ace_" + token.type.replace(/\./g, " ace_");
stringBuilder.push("<span class='", classes, "'>", output, "</span>");
}
else {
stringBuilder.push(output);
}
}
var splits = this.session.getRowSplitData(row);
var chars = 0, split = 0, splitChars;
if (!splits || splits.length == 0) {
splitChars = Number.MAX_VALUE;
} else {
splitChars = splits[0];
}
stringBuilder.push("<div style='height:",
this.config.lineHeight, "px",
"'>");
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
var value = token.value;
if (chars + value.length < splitChars) {
addToken(token, value);
chars += value.length;
} else {
while (chars + value.length >= splitChars) {
addToken(token, value.substring(0, splitChars - chars));
value = value.substring(splitChars - chars);
chars = splitChars;
stringBuilder.push("</div>",
"<div style='height:",
this.config.lineHeight, "px",
"'>");
split ++;
splitChars = splits[split] || Number.MAX_VALUE;
}
if (value.length != 0) {
chars += value.length;
addToken(token, value);
}
}
};
if (this.showInvisibles) {
@ -296,6 +339,7 @@ var Text = function(parentEl) {
stringBuilder.push("<span class='ace_invisible'>" + this.EOF_CHAR + "</span>");
}
}
stringBuilder.push("</div>");
};
}).call(Text.prototype);

View file

@ -17,13 +17,13 @@ oop.inherits(JavaScriptWorker, Mirror);
this.onUpdate = function() {
var value = this.doc.getValue();
var start = new Date();
// var start = new Date();
var parser = require("ace/narcissus/jsparse");
try {
parser.parse(value);
} catch(e) {
console.log("narcissus")
console.log(e);
// console.log("narcissus")
// console.log(e);
sender.emit("narcissus", {
row: e.lineno-1,
column: null, // TODO convert e.cursor
@ -32,14 +32,14 @@ oop.inherits(JavaScriptWorker, Mirror);
});
return;
} finally {
console.log("parse time: " + (new Date() - start));
// console.log("parse time: " + (new Date() - start));
}
var start = new Date();
console.log("jslint")
// var start = new Date();
// console.log("jslint")
lint(value, {undef: false, onevar: false, passfail: false});
this.sender.emit("jslint", lint.errors);
console.log("lint time: " + (new Date() - start));
// console.log("lint time: " + (new Date() - start));
}
}).call(JavaScriptWorker.prototype);

View file

@ -137,7 +137,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
this.clone = function() {
return Range.fromPoints(this.start, this.end);
};
this.collapseRows = function() {
if (this.end.column == 0)
return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0)
@ -145,10 +145,14 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
return new Range(this.start.row, 0, this.end.row, 0)
};
this.toScreenRange = function(doc) {
this.toScreenRange = function(session) {
var screenPosStart =
session.documentToScreenPosition(this.start);
var screenPosEnd =
session.documentToScreenPosition(this.end);
return new Range(
this.start.row, doc.documentToScreenColumn(this.start.row, this.start.column),
this.end.row, doc.documentToScreenColumn(this.end.row, this.end.column)
screenPosStart.row, screenPosStart.column,
screenPosEnd.row, screenPosEnd.column
);
};

View file

@ -20,6 +20,7 @@
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -165,11 +166,19 @@ var Selection = function(doc) {
this.setSelectionRange = function(range, reverse) {
if (reverse) {
this.setSelectionAnchor(range.end.row, range.end.column);
this.selectTo(range.start.row, range.start.column);
this.selectTo(range.start.row, range.start.column);
} else {
this.setSelectionAnchor(range.start.row, range.start.column);
this.selectTo(range.end.row, range.end.column);
}
this.$updateDesiredColumn();
};
this.$updateDesiredColumn = function() {
var cursor = this.getCursor();
if (cursor) {
this.$desiredColumn = this.doc.documentToScreenColumn(cursor.row, cursor.column);
}
};
this.$moveSelection = function(mover) {
@ -248,7 +257,7 @@ var Selection = function(doc) {
var column = cursor.column;
var range = this.doc.getWordRange(cursor.row, column);
this.setSelectionRange(range);
/*this.setSelectionAnchor(cursor.row, start);
this.$moveSelection(function() {
this.moveCursorTo(cursor.row, end);
@ -272,7 +281,7 @@ var Selection = function(doc) {
this.moveCursorLeft = function() {
if (this.selectionLead.column == 0) {
// cursor is a line start
// cursor is a line (start
if (this.selectionLead.row > 0) {
this.moveCursorTo(this.selectionLead.row - 1, this.doc
.getLine(this.selectionLead.row - 1).length);
@ -309,19 +318,27 @@ var Selection = function(doc) {
this.moveCursorLineStart = function() {
var row = this.selectionLead.row;
var column = this.selectionLead.column;
var beforeCursor = this.doc.getLine(row).slice(0, column);
var screenRow = this.doc.documentToScreenRow(row, column);
var firstRowColumn = this.doc.getScreenFirstRowColumn(screenRow);
var beforeCursor = this.doc.getLine(row).slice(firstRowColumn, column);
var leadingSpace = beforeCursor.match(/^\s*/);
if (leadingSpace[0].length == 0)
this.moveCursorTo(row, this.doc.getLine(row).match(/^\s*/)[0].length);
else if (leadingSpace[0].length >= column)
this.moveCursorTo(row, 0);
else
this.moveCursorTo(row, leadingSpace[0].length);
if (leadingSpace[0].length == 0) {
var lastRowColumn = this.doc.getDocumentLastRowColumn(row, column);
leadingSpace = this.doc.getLine(row).
substring(firstRowColumn, lastRowColumn).
match(/^\s*/);
this.moveCursorTo(row, firstRowColumn + leadingSpace[0].length);
} else if (leadingSpace[0].length >= column) {
this.moveCursorTo(row, firstRowColumn);
} else {
this.moveCursorTo(row, firstRowColumn + leadingSpace[0].length);
}
};
this.moveCursorLineEnd = function() {
this.moveCursorTo(this.selectionLead.row,
this.doc.getLine(this.selectionLead.row).length);
var selLead = this.selectionLead;
this.moveCursorTo(selLead.row,
this.doc.getDocumentLastRowColumn(selLead.row, selLead.column));
};
this.moveCursorFileEnd = function() {
@ -387,7 +404,21 @@ var Selection = function(doc) {
};
this.moveCursorBy = function(rows, chars) {
this.moveCursorTo(this.selectionLead.row + rows, this.selectionLead.column + chars);
if (this.doc.getUseWrapMode()) {
var screenPos = this.doc.documentToScreenPosition(
this.selectionLead.row, this.selectionLead.column);
var screenCol =
(chars == 0 && this.$desiredColumn) || screenPos.column;
var docPos = this.doc.screenToDocumentPosition(
screenPos.row + rows, screenCol);
this.moveCursorTo(docPos.row, docPos.column + chars, chars == 0);
} else {
var docColumn =
(chars == 0 && this.$desiredColumn) || this.selectionLead.column;
this.moveCursorTo(
this.selectionLead.row + rows, docColumn + chars, chars == 0);
}
};
@ -395,20 +426,17 @@ var Selection = function(doc) {
this.moveCursorTo(position.row, position.column);
};
this.moveCursorTo = function(row, column) {
this.moveCursorTo = function(row, column, preventUpdateDesiredColumn) {
var cursor = this.$clipPositionToDocument(row, column);
// only dispatch change if the cursor actually changed
if (cursor.row !== this.selectionLead.row || cursor.column !== this.selectionLead.column) {
this.selectionLead = cursor;
!preventUpdateDesiredColumn && this.$updateDesiredColumn(column);
this._dispatchEvent("changeCursor", { data: this.getCursor() });
}
};
this.moveCursorUp = function() {
this.moveCursorBy(-1, 0);
};
this.$clipPositionToDocument = function(row, column) {
var pos = {};

View file

@ -57,5 +57,5 @@ async.concat(
require("./mode/javascript_tokenizer_test"),
require("./mode/text_test"),
require("./mode/xml_test"),
require("./mode/xml_tokenizer_test")
require("./mode/xml_tokenizer_test")
).exec();

View file

@ -47,10 +47,10 @@ var EditSession = require("../edit_session").EditSession,
assert = require("./assertions");
var Test = {
setUp : function(next) {
this.session1 = new EditSession(["abc", "def"]);
this.session2 = new EditSession(["ghi", "jkl"]);
this.session2 = new EditSession(["ghi", "jkl"]);
this.editor = new Editor(new MockRenderer());
next();
},

View file

@ -20,6 +20,7 @@
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -36,10 +37,11 @@
* ***** END LICENSE BLOCK ***** */
var Document = require("../document").Document,
EditSession = require("../edit_session").EditSession,
Range = require("../range").Range,
assert = require("./assertions"),
async = require("asyncjs");
var Test = {
"test: insert text in line" : function() {
@ -47,194 +49,194 @@ var Test = {
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.insert({row: 0, column: 1}, "juhu");
assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n"));
var d = deltas.concat();
var d = deltas.concat();
doc.revertDeltas(d);
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
doc.applyDeltas(d);
assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n"));
},
"test: insert new line" : function() {
var doc = new Document(["12", "34"]);
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.insertNewLine({row: 0, column: 1});
assert.equal(doc.getValue(), ["1", "2", "34"].join("\n"));
var d = deltas.concat();
var d = deltas.concat();
doc.revertDeltas(d);
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
doc.applyDeltas(d);
assert.equal(doc.getValue(), ["1", "2", "34"].join("\n"));
},
"test: insert lines at the beginning" : function() {
var doc = new Document(["12", "34"]);
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.insertLines(0, ["aa", "bb"]);
assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n"));
var d = deltas.concat();
var d = deltas.concat();
doc.revertDeltas(d);
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
doc.applyDeltas(d);
assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n"));
},
"test: insert lines at the end" : function() {
var doc = new Document(["12", "34"]);
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.insertLines(2, ["aa", "bb"]);
assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n"));
},
"test: insert lines in the middle" : function() {
var doc = new Document(["12", "34"]);
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.insertLines(1, ["aa", "bb"]);
assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n"));
var d = deltas.concat();
var d = deltas.concat();
doc.revertDeltas(d);
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
doc.applyDeltas(d);
assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n"));
},
"test: insert multi line string at the start" : function() {
var doc = new Document(["12", "34"]);
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.insert({row: 0, column: 0}, "aa\nbb\ncc");
assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n"));
var d = deltas.concat();
var d = deltas.concat();
doc.revertDeltas(d);
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
doc.applyDeltas(d);
assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n"));
},
"test: insert multi line string at the end" : function() {
var doc = new Document(["12", "34"]);
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.insert({row: 2, column: 0}, "aa\nbb\ncc");
assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n"));
var d = deltas.concat();
var d = deltas.concat();
doc.revertDeltas(d);
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
doc.applyDeltas(d);
assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n"));
},
"test: insert multi line string in the middle" : function() {
var doc = new Document(["12", "34"]);
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.insert({row: 0, column: 1}, "aa\nbb\ncc");
assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n"));
var d = deltas.concat();
var d = deltas.concat();
doc.revertDeltas(d);
assert.equal(doc.getValue(), ["12", "34"].join("\n"));
doc.applyDeltas(d);
assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n"));
},
"test: delete in line" : function() {
var doc = new Document(["1234", "5678"]);
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.remove(new Range(0, 1, 0, 3));
assert.equal(doc.getValue(), ["14", "5678"].join("\n"));
var d = deltas.concat();
var d = deltas.concat();
doc.revertDeltas(d);
assert.equal(doc.getValue(), ["1234", "5678"].join("\n"));
doc.applyDeltas(d);
assert.equal(doc.getValue(), ["14", "5678"].join("\n"));
},
"test: delete new line" : function() {
var doc = new Document(["1234", "5678"]);
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.remove(new Range(0, 4, 1, 0));
assert.equal(doc.getValue(), ["12345678"].join("\n"));
var d = deltas.concat();
var d = deltas.concat();
doc.revertDeltas(d);
assert.equal(doc.getValue(), ["1234", "5678"].join("\n"));
doc.applyDeltas(d);
assert.equal(doc.getValue(), ["12345678"].join("\n"));
},
"test: delete multi line range line" : function() {
var doc = new Document(["1234", "5678", "abcd"]);
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.remove(new Range(0, 2, 2, 2));
assert.equal(doc.getValue(), ["12cd"].join("\n"));
var d = deltas.concat();
var d = deltas.concat();
doc.revertDeltas(d);
assert.equal(doc.getValue(), ["1234", "5678", "abcd"].join("\n"));
doc.applyDeltas(d);
assert.equal(doc.getValue(), ["12cd"].join("\n"));
},
"test: delete full lines" : function() {
var doc = new Document(["1234", "5678", "abcd"]);
var deltas = [];
doc.on("change", function(e) { deltas.push(e.data); });
doc.remove(new Range(1, 0, 3, 0));
assert.equal(doc.getValue(), ["1234", ""].join("\n"));
},
"test: remove lines should return the removed lines" : function() {
var doc = new Document(["1234", "5678", "abcd"]);
var removed = doc.removeLines(1, 2);
assert.equal(removed.join("\n"), ["5678", "abcd"].join("\n"));
},
@ -246,7 +248,7 @@ var Test = {
"test: should handle windows style new lines" : function() {
var doc = new Document(["1", "2", "3"].join("\r\n"));
doc.setNewLineMode("unix");
assert.equal(doc.getValue(), ["1", "2", "3"].join("\n"));
},
@ -259,24 +261,108 @@ var Test = {
"test: set new line mode to 'unix' should use '\n' as new lines": function() {
var doc = new Document(["1", "2", "3"].join("\r\n"));
doc.setNewLineMode("unix");
assert.equal(doc.getValue(), ["1", "2", "3"].join("\n"));
},
"test: set new line mode to 'auto' should detect the incoming nl type": function() {
var doc = new Document(["1", "2", "3"].join("\n"));
doc.setNewLineMode("auto");
assert.equal(doc.getValue(), ["1", "2", "3"].join("\n"));
var doc = new Document(["1", "2", "3"].join("\r\n"));
doc.setNewLineMode("auto");
assert.equal(doc.getValue(), ["1", "2", "3"].join("\r\n"));
doc.replace(new Range(0, 0, 2, 1), ["4", "5", "6"].join("\n"));
assert.equal(["4", "5", "6"].join("\n"), doc.getValue());
},
"test: wrapLine split function" : function() {
var splits;
var computeWrapSplits = EditSession.prototype.$computeWrapSplits;
var c = 0;
function computeAndAssert(line, assertEqual, wrapLimit, tabSize) {
wrapLimit = wrapLimit || 12;
tabSize = tabSize || 4;
splits = computeWrapSplits.call(EditSession.prototype, line, wrapLimit, tabSize);
console.log("String:", line, "Result:", splits, "Expected:", assertEqual);
assert.ok(splits.length == assertEqual.length);
for (var i = 0; i < splits.length; i++) {
assert.ok(splits[i] == assertEqual[i]);
}
}
// Basic splitting.
computeAndAssert("foo bar foo bar", [ 12 ]);
computeAndAssert("foo bar f bar", [ 12 ]);
computeAndAssert("foo bar f r", [ 14 ]);
computeAndAssert("foo bar foo bar foo bara foo", [12, 25]);
// Don't split if there is only whitespaces/tabs at the end of the line.
computeAndAssert("foo foo foo \t \t", [ ]);
// If there is no space to split, force split.
computeAndAssert("foooooooooooooo", [ 12 ]);
computeAndAssert("fooooooooooooooooooooooooooo", [12, 24]);
computeAndAssert("foo bar fooooooooooobooooooo", [8, 20]);
// Basic splitting + tabs.
computeAndAssert("foo \t\tbar", [ 6 ]);
computeAndAssert("foo \t \tbar", [ 7 ]);
// Ignore spaces/tabs at beginning of split.
computeAndAssert("foo \t \t \t \t bar", [ 14 ]);
// Test wrapping for asian characters.
computeAndAssert("ぁぁ", [1], 2);
computeAndAssert(" ぁぁ", [1, 2], 2);
computeAndAssert(" ぁ\tぁ", [1, 3], 2);
computeAndAssert(" ぁぁ\tぁ", [1, 4], 4);
},
"test: documentToScreen": function() {
var tabSize = 4;
var wrapLimit = 12;
var session = new EditSession(["foo bar foo bar"]);
session.setUseWrapMode(true);
session.setWrapLimit(12);
assert.position(session.documentToScreenPosition(0, 11), 0, 11);
assert.position(session.documentToScreenPosition(0, 12), 1, 0);
session = new EditSession(["ぁぁa"]);
session.setUseWrapMode(true);
session.setWrapLimit(2);
assert.position(session.documentToScreenPosition(0, 1), 1, 0);
assert.position(session.documentToScreenPosition(0, 2), 2, 0);
assert.position(session.documentToScreenPosition(0, 4), 2, 1);
},
"test: screenToDocument": function() {
var tabSize = 4;
var wrapLimit = 12;
var session = new EditSession(["foo bar foo bar"]);
session.setUseWrapMode(true);
session.setWrapLimit(12);
assert.position(session.screenToDocumentPosition(1, 0), 0, 12);
assert.position(session.screenToDocumentPosition(0, 11), 0, 11);
// Check if the position is clamped the right way.
assert.position(session.screenToDocumentPosition(0, 12), 0, 11);
assert.position(session.screenToDocumentPosition(0, 20), 0, 11);
session = new EditSession(["ぁ a"]);
session.setUseWrapMode(true);
assert.position(session.screenToDocumentPosition(0, 1), 0, 0);
assert.position(session.screenToDocumentPosition(0, 2), 0, 1);
assert.position(session.screenToDocumentPosition(0, 3), 0, 2);
assert.position(session.screenToDocumentPosition(0, 4), 0, 3);
assert.position(session.screenToDocumentPosition(0, 5), 0, 3);
}
};
@ -285,4 +371,4 @@ module.exports = require("asyncjs/test").testcase(Test);
if (module === require.main) {
require("../../../support/paths");
exports.exec()
}
}

View file

@ -43,7 +43,7 @@ var EditSession = require("ace/edit_session").EditSession,
Range = require("ace/range").Range,
assert = require("./assertions"),
async = require("asyncjs");
var Test = {
"test: find matching opening bracket" : function() {
@ -81,16 +81,16 @@ var Test = {
"test: move lines down" : function() {
var session = new EditSession(["a1", "a2", "a3", "a4"]);
session.moveLinesDown(0, 1);
assert.equal(session.getValue(), ["a3", "a1", "a2", "a4"].join("\n"));
session.moveLinesDown(1, 2);
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
session.moveLinesDown(2, 3);
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
session.moveLinesDown(2, 2);
assert.equal(session.getValue(), ["a3", "a4", "a2", "a1"].join("\n"));
},
@ -100,13 +100,13 @@ var Test = {
session.moveLinesUp(2, 3);
assert.equal(session.getValue(), ["a1", "a3", "a4", "a2"].join("\n"));
session.moveLinesUp(1, 2);
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
session.moveLinesUp(0, 1);
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
session.moveLinesUp(2, 2);
assert.equal(session.getValue(), ["a3", "a1", "a4", "a2"].join("\n"));
},
@ -177,57 +177,57 @@ var Test = {
assert.equal(session.screenToDocumentColumn(0, 15), 12);
assert.equal(session.screenToDocumentColumn(0, 19), 13);
},
"test: insert text in multiple rows": function() {
var session = new EditSession(["12", "", "abcd"]);
var inserted = session.multiRowInsert([0, 1, 2], 2, "juhu 1");
assert.equal(inserted.rows, 0);
assert.equal(inserted.columns, 6);
assert.equal(session.getValue(), ["12juhu 1", " juhu 1", "abjuhu 1cd"].join("\n"));
},
"test: undo insert text in multiple rows": function() {
var session = new EditSession(["12", "", "abcd"]);
var undoManager = new UndoManager();
session.setUndoManager(undoManager);
session.multiRowInsert([0, 1, 2], 2, "juhu 1");
session.$informUndoManager.call();
assert.equal(session.getValue(), ["12juhu 1", " juhu 1", "abjuhu 1cd"].join("\n"));
undoManager.undo();
assert.equal(session.getValue(), ["12", "", "abcd"].join("\n"));
undoManager.redo();
assert.equal(session.getValue(), ["12juhu 1", " juhu 1", "abjuhu 1cd"].join("\n"));
},
"test: insert new line in multiple rows": function() {
var session = new EditSession(["12", "", "abcd"]);
var inserted = session.multiRowInsert([0, 1, 2], 2, "\n");
assert.equal(inserted.rows, 1);
assert.equal(session.getValue(), ["12\n", " \n", "ab\ncd"].join("\n"));
},
"test: insert multi line text in multiple rows": function() {
var session = new EditSession(["12", "", "abcd"]);
var inserted = session.multiRowInsert([0, 1, 2], 2, "juhu\n12");
assert.equal(inserted.rows, 1);
assert.equal(session.getValue(), ["12juhu\n12", " juhu\n12", "abjuhu\n12cd"].join("\n"));
},
"test: remove right in multiple rows" : function() {
var session = new EditSession(["12", "", "abcd"]);
session.multiRowRemove([0, 1, 2], new Range(0, 2, 0, 3));
assert.equal(session.getValue(), ["12", "", "abd"].join("\n"));
},
"test: undo remove right in multiple rows" : function() {
var session = new EditSession(["12", "", "abcd"]);
var undoManager = new UndoManager();
@ -236,33 +236,43 @@ var Test = {
session.multiRowRemove([0, 1, 2], new Range(0, 1, 0, 3));
session.$informUndoManager.call();
assert.equal(session.getValue(), ["1", "", "ad"].join("\n"));
undoManager.undo();
assert.equal(session.getValue(), ["12", "", "abcd"].join("\n"));
undoManager.redo();
assert.equal(session.getValue(), ["1", "", "ad"].join("\n"));
},
"test get longest line" : function() {
var session = new EditSession(["12"]);
session.setTabSize(4);
assert.equal(session.getWidth(), 2);
assert.equal(session.getScreenWidth(), 2);
session.doc.insertNewLine(0);
session.doc.insertLines(1, ["123"]);
assert.equal(session.getWidth(), 3);
assert.equal(session.getScreenWidth(), 3);
session.doc.insertNewLine(0);
session.doc.insertLines(1, ["\t\t"]);
assert.equal(session.getWidth(), 3);
assert.equal(session.getScreenWidth(), 8);
session.setTabSize(2);
assert.equal(session.getWidth(), 3);
assert.equal(session.getScreenWidth(), 4);
},
"test getDisplayString": function() {
var session = new EditSession(["12"]);
session.setTabSize(4);
assert.equal(session.$getDisplayTokens("\t").length, 4);
assert.equal(session.$getDisplayTokens("abc").length, 3);
assert.equal(session.$getDisplayTokens("abc\t").length, 7);
}
};

View file

@ -50,6 +50,8 @@ MockRenderer = function(visibleRowCount) {
firstVisibleRow : 0,
lastVisibleRow : this.visibleRowCount
};
this.isMockRenderer = true;
};
@ -117,10 +119,10 @@ MockRenderer.prototype.addMarker = function() {
MockRenderer.prototype.setBreakpoints = function() {
};
MockRenderer.prototype.updateFull = function() {
MockRenderer.prototype.updateFull = function() {
};
MockRenderer.prototype.updateText = function() {
MockRenderer.prototype.updateText = function() {
};
MockRenderer.prototype.showCursor = function() {
@ -132,5 +134,12 @@ MockRenderer.prototype.visualizeFocus = function() {
MockRenderer.prototype.setAnnotations = function() {
};
MockRenderer.prototype.textToScreenCoordinates = function() {
return {
pageX: 0,
pageY: 0
}
};
return MockRenderer;
});

View file

@ -132,32 +132,32 @@ var Test = {
var range = range.extend(2, 5);
assert.range(range, 2, 5, 2, 30);
var range = range.extend(2, 35);
assert.range(range, 2, 5, 2, 35);
var range = range.extend(2, 15);
assert.range(range, 2, 5, 2, 35);
var range = range.extend(1, 4);
assert.range(range, 1, 4, 2, 35);
var range = range.extend(6, 10);
assert.range(range, 1, 4, 6, 10);
},
"test: collapse rows" : function() {
var range = new Range(0, 2, 1, 2);
assert.range(range.collapseRows(), 0, 0, 1, 0);
assert.range(range.collapseRows(), 0, 0, 1, 0);
var range = new Range(2, 2, 3, 1);
assert.range(range.collapseRows(), 2, 0, 3, 0);
assert.range(range.collapseRows(), 2, 0, 3, 0);
var range = new Range(2, 2, 3, 0);
assert.range(range.collapseRows(), 2, 0, 2, 0);
assert.range(range.collapseRows(), 2, 0, 2, 0);
var range = new Range(2, 0, 2, 0);
assert.range(range.collapseRows(), 2, 0, 2, 0);
assert.range(range.collapseRows(), 2, 0, 2, 0);
}
};

View file

@ -126,19 +126,19 @@ var Test = {
"test: indent selected lines" : function() {
var session = new EditSession(["a12345", "b12345", "c12345"].join("\n"));
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 0);
editor.getSelection().selectDown();
editor.indent();
assert.equal(["a12345", " b12345", "c12345"].join("\n"), session.toString());
},
"test: no auto indent if cursor is before the {" : function() {
var session = new EditSession("{", new JavaScriptMode());
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(0, 0);
editor.moveCursorTo(0, 0);
editor.onTextInput("\n");
assert.equal(["", "{"].join("\n"), session.toString());
},
@ -149,7 +149,7 @@ var Test = {
editor.moveCursorTo(0, 5);
editor.getSelection().selectDown();
editor.getSelection().selectDown();
editor.getSelection().selectDown();
editor.blockOutdent();
assert.equal(session.toString(), [" a12345", "b12345", " c12345"].join("\n"));
@ -208,21 +208,21 @@ var Test = {
assert.equal([" abc", "cde"].join("\n"), session.toString());
assert.range(editor.getSelectionRange(), 0, 0, 1, 1);
},
"test: toggle comment lines twice should return the original text" : function() {
var session = new EditSession([" abc", "cde", "fg"], new JavaScriptMode());
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(0, 0);
editor.getSelection().selectDown();
editor.getSelection().selectDown();
editor.toggleCommentLines();
editor.toggleCommentLines();
assert.equal([" abc", "cde", "fg"].join("\n"), session.toString());
},
"test: comment lines - if the selection end is at the line start it should stay there": function() {
//select down
@ -366,71 +366,71 @@ var Test = {
editor.onTextInput("\t");
assert.equal(session.toString(), "\t");
},
"test: undo/redo for delete line" : function() {
var session = new EditSession(["111", "222", "333"]);
var undoManager = new UndoManager();
session.setUndoManager(undoManager);
var initialText = session.toString();
var editor = new Editor(new MockRenderer(), session);
editor.removeLines();
var step1 = session.toString();
assert.equal(step1, "222\n333");
session.$informUndoManager.call();
editor.removeLines();
var step2 = session.toString();
assert.equal(step2, "333");
session.$informUndoManager.call();
editor.removeLines();
var step3 = session.toString();
assert.equal(step3, "");
session.$informUndoManager.call();
undoManager.undo();
session.$informUndoManager.call();
assert.equal(session.toString(), step2);
undoManager.undo();
session.$informUndoManager.call();
assert.equal(session.toString(), step1);
undoManager.undo();
session.$informUndoManager.call();
assert.equal(session.toString(), initialText);
undoManager.undo();
session.$informUndoManager.call();
assert.equal(session.toString(), initialText);
},
"test: remove left should remove character left of the cursor" : function() {
var session = new EditSession(["123", "456"]);
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 1);
editor.removeLeft();
assert.equal(session.toString(), "123\n56");
},
"test: remove left should remove line break if cursor is at line start" : function() {
var session = new EditSession(["123", "456"]);
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 0);
editor.removeLeft();
assert.equal(session.toString(), "123456");
},
"test: remove left should remove tabsize spaces if cursor is on a tab stop and preceeded by spaces" : function() {
var session = new EditSession(["123", " 456"]);
session.setUseSoftTabs(true);
session.setTabSize(4);
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 8);
editor.removeLeft();

View file

@ -22,6 +22,7 @@
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -115,12 +116,11 @@ var VirtualRenderer = function(container, theme) {
this.$loop = new RenderLoop(this.$renderChanges.bind(this));
this.$loop.schedule(this.CHANGE_FULL);
this.$updatePrintMargin();
this.setPadding(4);
this.$updatePrintMargin();
};
(function() {
this.showGutter = true;
this.CHANGE_CURSOR = 1;
@ -138,8 +138,8 @@ var VirtualRenderer = function(container, theme) {
this.session = session;
this.$cursorLayer.setSession(session);
this.$markerLayer.setSession(session);
this.$gutterLayer.setSession(session);
this.$textLayer.setSession(session);
this.$loop.schedule(this.CHANGE_FULL);
};
@ -184,11 +184,11 @@ var VirtualRenderer = function(container, theme) {
/**
* Triggers resize of the editor
*/
this.onResize = function() {
this.onResize = function(force) {
var changes = this.CHANGE_SIZE;
var height = dom.getInnerHeight(this.container);
if (this.$size.height != height) {
if (force || this.$size.height != height) {
this.$size.height = height;
this.scroller.style.height = height + "px";
@ -201,7 +201,7 @@ var VirtualRenderer = function(container, theme) {
}
var width = dom.getInnerWidth(this.container);
if (this.$size.width != width) {
if (force || this.$size.width != width) {
this.$size.width = width;
var gutterWidth = this.showGutter ? this.$gutter.offsetWidth : 0;
@ -264,10 +264,7 @@ var VirtualRenderer = function(container, theme) {
return;
this.$gutter.style.display = show ? "block" : "none";
this.showGutter = show;
// set fake width to make onResize work
this.$size.width = -1
this.onResize();
this.$gutterLayer.update(this.layerConfig)
this.onResize(true);
}
this.$updatePrintMargin = function() {
@ -285,7 +282,7 @@ var VirtualRenderer = function(container, theme) {
}
var style = this.$printMarginEl.style;
style.left = (this.characterWidth * this.$printMarginColumn) + "px";
style.left = ((this.characterWidth * this.$printMarginColumn) + this.$padding * 2) + "px";
style.visibility = this.$showPrintMargin ? "visible" : "hidden";
};
@ -297,6 +294,19 @@ var VirtualRenderer = function(container, theme) {
return this.content;
};
this.getTextAreaContainer = function() {
return this.scroller;
};
this.moveTextAreaToCursor = function(textarea) {
var pos = this.$cursorLayer.getPixelPosition();
if (!pos)
return;
textarea.style.left = (pos.left + this.$padding) + "px";
textarea.style.top = pos.top + "px";
};
this.getFirstVisibleRow = function() {
return (this.layerConfig || {}).firstRow || 0;
};
@ -325,6 +335,7 @@ var VirtualRenderer = function(container, theme) {
this.$padding = padding;
this.content.style.padding = "0 " + padding + "px";
this.$loop.schedule(this.CHANGE_FULL);
this.$updatePrintMargin();
};
this.onScroll = function(e) {
@ -332,14 +343,14 @@ var VirtualRenderer = function(container, theme) {
};
this.$updateScrollBar = function() {
this.scrollBar.setInnerHeight(this.session.getLength() * this.lineHeight);
this.scrollBar.setInnerHeight(this.session.getScreenLength() * this.lineHeight);
this.scrollBar.setScrollTop(this.scrollTop);
};
this.$renderChanges = function(changes) {
if (!changes || !this.session || !this.$tokenizer)
return;
// text, scrolling and resize changes can cause the view port size to change
if (!this.layerConfig ||
changes & this.CHANGE_FULL ||
@ -357,6 +368,7 @@ var VirtualRenderer = function(container, theme) {
this.$markerLayer.update(this.layerConfig);
this.$cursorLayer.update(this.layerConfig);
this.$updateScrollBar();
this.scrollCursorIntoView();
return;
}
@ -397,20 +409,36 @@ var VirtualRenderer = function(container, theme) {
};
this.$computeLayerConfig = function() {
var session = this.session;
var offset = this.scrollTop % this.lineHeight;
var minHeight = this.$size.scrollerHeight + this.lineHeight;
var longestLine = this.$getLongestLine();
var widthChanged = !this.layerConfig ? true : (this.layerConfig.width != longestLine);
var lineCount = Math.ceil(minHeight / this.lineHeight);
var lineCount = Math.ceil(minHeight / this.lineHeight) - 1;
var firstRow = Math.max(0, Math.round((this.scrollTop - offset) / this.lineHeight));
var lastRow = Math.max(0, Math.min(this.session.getLength(), firstRow + lineCount) - 1);
var lastRow = firstRow + lineCount;
// Map lines on the screen to lines in the document.
var firstRowScreen, firstRowHeight;
var lineHeight = { lineHeight: this.lineHeight };
firstRow = session.screenToDocumentRow(firstRow);
firstRowScreen = session.documentToScreenRow(firstRow);
firstRowHeight = session.getRowHeight(lineHeight, firstRow);
lastRow = Math.min(session.screenToDocumentRow(lastRow), session.getLength() - 1);
minHeight = this.$size.scrollerHeight + session.getRowHeight(lineHeight, lastRow)+
firstRowHeight;
offset = this.scrollTop - firstRowScreen * this.lineHeight;
var layerConfig = this.layerConfig = {
width : longestLine,
padding : this.$padding,
firstRow : firstRow,
firstRowScreen: firstRowScreen,
lastRow : lastRow,
lineHeight : this.lineHeight,
characterWidth : this.characterWidth,
@ -545,7 +573,7 @@ var VirtualRenderer = function(container, theme) {
};
this.scrollToY = function(scrollTop) {
var maxHeight = this.session.getLength() * this.lineHeight - this.$size.scrollerHeight;
var maxHeight = this.session.getScreenLength() * this.lineHeight - this.$size.scrollerHeight;
var scrollTop = Math.max(0, Math.min(maxHeight, scrollTop));
if (this.scrollTop !== scrollTop) {
@ -574,17 +602,15 @@ var VirtualRenderer = function(container, theme) {
var row = Math.floor((pageY + this.scrollTop - canvasPos.top)
/ this.lineHeight);
return {
row : row,
column : this.session.screenToDocumentColumn(Math.max(0, Math.min(row, this.session.getLength()-1)), col)
};
return this.session.screenToDocumentPosition(row, Math.max(col, 0));
};
this.textToScreenCoordinates = function(row, column) {
var canvasPos = this.scroller.getBoundingClientRect();
var pos = this.session.documentToScreenPosition(row, column);
var x = this.$padding + Math.round(this.session.documentToScreenColumn(row, column) * this.characterWidth);
var y = row * this.lineHeight;
var x = this.$padding + Math.round(pos.column * this.characterWidth);
var y = pos.row * this.lineHeight;
return {
pageX: canvasPos.left + x - this.getScrollLeft(),
@ -601,7 +627,6 @@ var VirtualRenderer = function(container, theme) {
};
this.showComposition = function(position) {
console.log("show composition")
if (!this.$composition) {
this.$composition = document.createElement("div");
this.$composition.className = "ace_composition";
@ -609,19 +634,18 @@ var VirtualRenderer = function(container, theme) {
}
this.$composition.innerHTML = "&nbsp;";
var pos = this.$cursorLayer.getPixelPosition();
var style = this.$composition.style;
style.top = pos.top + "px";
style.left = (pos.left + this.$padding) + "px";
style.height = this.lineHeight + "px";
//style.width = this.characterWidth + "px";
this.hideCursor();
};
this.setCompositionText = function(text) {
this.$composition.innerText = this.$composition.textContent = text;
dom.setInnerText(this.$composition, text);
};
this.hideComposition = function() {
@ -629,7 +653,7 @@ var VirtualRenderer = function(container, theme) {
if (!this.$composition)
return;
var style = this.$composition.style;
style.top = "-10000px";
style.left = "-10000px";

View file

@ -16,10 +16,10 @@ var WorkerClient = function(baseUrl, topLevelNamespaces, module, classname) {
this.callbacks = [];
if (require.packaged) {
var worker = this.$worker = new Worker("host.js");
var worker = this.$worker = new Worker("worker.js");
}
else {
var workerUrl = require.nameToUrl("ace/worker/host", null, "_");
var workerUrl = require.nameToUrl("ace/worker/worker", null, "_");
var worker = this.$worker = new Worker(workerUrl);
var tlns = {};

View file

@ -28,7 +28,7 @@
"asyncjs": ">=0.0.2",
"jsdom": ">=0.1.23",
"htmlparser": ">=1.7.2",
"dryice": ">=0.1.0"
"dryice": ">=0.2.1"
},
"licenses": [{
"type": "MPL",

View file

@ -1,4 +1,6 @@
require("./requireJS-node");
require.paths.unshift(__dirname + "/../lib");
require.paths.unshift(__dirname + "/pilot/lib");
require.paths.unshift(__dirname);
require.paths.unshift(__dirname + "/async/lib");
require.paths.unshift(__dirname + "/jsdom/lib");
require.paths.unshift(__dirname);

@ -1 +1 @@
Subproject commit af90344687c8486892b44d5decc4c2181df3a6cf
Subproject commit 5474f1715dcc199a0c69211c89b594b9f569d9ed