This commit is contained in:
William Candillon 2012-06-04 09:50:22 +02:00
commit cc8dd79c3f
74 changed files with 1954 additions and 1047 deletions

View file

@ -240,12 +240,9 @@ var BackgroundTokenizer = function(tokenizer, editor) {
var data = this.tokenizer.getLineTokens(line, state);
if (overflow) {
data.tokens.push(overflow);
data.state = null;
data.state = "start";
}
if (data.state == "start" && this.states[row] == null)
this.states[row] = "start";
if (this.states[row] !== data.state) {
this.states[row] = data.state;
this.lines[row + 1] = null;

View file

@ -0,0 +1,92 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Harutyun Amirjanyan <harutyun@c9.io>
*
* 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
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("amd-loader");
}
define(function(require, exports, module) {
"use strict";
var EditSession = require("./edit_session").EditSession;
var JavaScriptMode = require("./mode/javascript").Mode;
var Range = require("./range").Range;
var assert = require("./test/assertions");
function forceTokenize(session){
for (var i = 0, l = session.getLength(); i < l; i++)
session.getTokens(i)
}
function testStates(session, states) {
for (var i = 0, l = session.getLength(); i < l; i++)
assert.equal(session.bgTokenizer.states[i], states[i])
assert.ok(l == states.length)
}
module.exports = {
"test background tokenizer update on session change" : function() {
var doc = new EditSession([
"/*",
"*/",
"var juhu"
]);
doc.setMode("./mode/javascript")
forceTokenize(doc)
testStates(doc, ["comment", "start", "start"])
doc.remove(new Range(0,2,1,2))
testStates(doc, [null, "start"])
forceTokenize(doc)
testStates(doc, ["comment", "comment"])
doc.insert({row:0, column:2}, "\n*/")
testStates(doc, [undefined, undefined, "comment"])
forceTokenize(doc)
testStates(doc, ["comment", "start", "start"])
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}

View file

@ -51,16 +51,11 @@ oop.inherits(CommandManager, HashHandler);
if (editor && editor.$readOnly && !command.readOnly)
return false;
try {
var retvalue = this._emit("exec", {
editor: editor,
command: command,
args: args
});
} catch (e) {
window.console && window.console.log(e);
return true;
}
var retvalue = this._emit("exec", {
editor: editor,
command: command,
args: args
});
return retvalue === false ? false : true;
};

View file

@ -79,12 +79,15 @@ exports.defaultCommands = [{
exec: function(editor) { editor.selectMore(1, true); },
bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"},
readonly: true
}, {
}, {
name: "splitIntoLines",
exec: function(editor) { editor.multiSelect.splitIntoLines(); },
bindKey: {win: "Ctrl-Shift-L", mac: "Ctrl-Shift-L"},
readonly: true
}, {
}];
// commands active in multiselect mode
exports.multiSelectCommands = [{
name: "singleSelection",
bindKey: "esc",
exec: function(editor) { editor.exitMultiSelectMode(); },
@ -92,10 +95,7 @@ exports.defaultCommands = [{
isAvailable: function(editor) {return editor.inMultiSelectMode}
}];
// commands active in multiselect mode
exports.multiEditCommands = {"singleSelection": "esc"};
var HashHandler = require("../keyboard/hash_handler").HashHandler;
exports.keyboardHandler = new HashHandler(exports.multiEditCommands);
exports.keyboardHandler = new HashHandler(exports.multiSelectCommands);
});

View file

@ -55,14 +55,14 @@ var options = {
exports.get = function(key) {
if (!options.hasOwnProperty(key))
throw new Error("Unknown confik key: " + key);
throw new Error("Unknown config key: " + key);
return options[key];
};
exports.set = function(key, value) {
if (!options.hasOwnProperty(key))
throw new Error("Unknown confik key: " + key);
throw new Error("Unknown config key: " + key);
options[key] = value;
};

View file

@ -18,13 +18,6 @@
cursor: text;
}
.ace_composition {
position: absolute;
background: #555;
color: #DDD;
z-index: 4;
}
.ace_gutter {
position: absolute;
overflow : hidden;
@ -34,12 +27,6 @@
z-index: 4;
}
.ace_gutter_active_line {
position: absolute;
left: 0;
right: 0;
}
.ace_scroller.horscroll {
box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;
}
@ -95,8 +82,8 @@
height: 100%;
}
.ace_editor textarea {
position: fixed;
.ace_editor > textarea {
position: absolute;
z-index: 0;
width: 0.5em;
height: 1em;
@ -110,6 +97,15 @@
overflow: hidden;
}
.ace_editor > textarea.ace_composition {
background: #fff;
color: #000;
z-index: 1000;
opacity: 1;
border: solid lightgray 1px;
margin: -1px
}
.ace_layer {
z-index: 1;
position: absolute;
@ -196,13 +192,13 @@
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
display: inline-block;
height: 11px;
margin-top: -2px;
vertical-align: middle;
background-image:
background-image:
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%11%00%00%00%09%08%06%00%00%00%D4%E8%C7%0C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%B5IDAT(%15%A5%91%3D%0E%02!%10%85ac%E1%05%D6%CE%D6%C6%CE%D2%E8%ED%CD%DE%C0%C6%D6N.%E0V%F8%3D%9Ca%891XH%C2%BE%D9y%3F%90!%E6%9C%C3%BFk%E5%011%C6-%F5%C8N%04%DF%BD%FF%89%DFt%83DN%60%3E%F3%AB%A0%DE%1A%5Dg%BE%10Q%97%1B%40%9C%A8o%10%8F%5E%828%B4%1B%60%87%F6%02%26%85%1Ch%1E%C1%2B%5Bk%FF%86%EE%B7j%09%9A%DA%9B%ACe%A3%F9%EC%DA!9%B4%D5%A6%81%86%86%98%CC%3C%5B%40%FA%81%B3%E9%CB%23%94%C16Azo%05%D4%E1%C1%95a%3B%8A'%A0%E8%CC%17%22%85%1D%BA%00%A2%FA%DC%0A%94%D1%D1%8D%8B%3A%84%17B%C7%60%1A%25Z%FC%8D%00%00%00%00IEND%AEB%60%82"),
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%007%08%06%00%00%00%C4%DD%80C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%3AIDAT8%11c%FC%FF%FF%7F%18%03%1A%60%01%F2%3F%A0%891%80%04%FF%11-%F8%17%9BJ%E2%05%B1ZD%81v%26t%E7%80%F8%A3%82h%A12%1A%20%A3%01%02%0F%01%BA%25%06%00%19%C0%0D%AEF%D5%3ES%00%00%00%00IEND%AEB%60%82");
background-repeat: no-repeat, repeat-x;
@ -213,7 +209,7 @@
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
cursor: pointer;
pointer-events: auto;
}
@ -222,7 +218,7 @@
}
.ace_fold:hover{
background-image:
background-image:
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%11%00%00%00%09%08%06%00%00%00%D4%E8%C7%0C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%B5IDAT(%15%A5%91%3D%0E%02!%10%85ac%E1%05%D6%CE%D6%C6%CE%D2%E8%ED%CD%DE%C0%C6%D6N.%E0V%F8%3D%9Ca%891XH%C2%BE%D9y%3F%90!%E6%9C%C3%BFk%E5%011%C6-%F5%C8N%04%DF%BD%FF%89%DFt%83DN%60%3E%F3%AB%A0%DE%1A%5Dg%BE%10Q%97%1B%40%9C%A8o%10%8F%5E%828%B4%1B%60%87%F6%02%26%85%1Ch%1E%C1%2B%5Bk%FF%86%EE%B7j%09%9A%DA%9B%ACe%A3%F9%EC%DA!9%B4%D5%A6%81%86%86%98%CC%3C%5B%40%FA%81%B3%E9%CB%23%94%C16Azo%05%D4%E1%C1%95a%3B%8A'%A0%E8%CC%17%22%85%1D%BA%00%A2%FA%DC%0A%94%D1%D1%8D%8B%3A%84%17B%C7%60%1A%25Z%FC%8D%00%00%00%00IEND%AEB%60%82"),
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%007%08%06%00%00%00%C4%DD%80C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%003IDAT8%11c%FC%FF%FF%7F%3E%03%1A%60%01%F2%3F%A3%891%80%04%FFQ%26%F8w%C0%B43%A1%DB%0C%E2%8F%0A%A2%85%CAh%80%8C%06%08%3C%04%E8%96%18%00%A3S%0D%CD%CF%D8%C1%9D%00%00%00%00IEND%AEB%60%82");
background-repeat: no-repeat, repeat-x;
@ -247,7 +243,7 @@
height: 14px;
width: 11px;
vertical-align: text-bottom;
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAe%8A%B1%0D%000%0C%C2%F2%2CK%96%BC%D0%8F9%81%88H%E9%D0%0E%96%C0%10%92%3E%02%80%5E%82%E4%A9*-%EEsw%C8%CC%11%EE%96w%D8%DC%E9*Eh%0C%151(%00%00%00%00IEND%AEB%60%82");
background-repeat: no-repeat;
background-position: center 5px;
@ -292,23 +288,19 @@
}
.ace_fade-fold-widgets .ace_fold-widget {
-moz-transition: 0.5s opacity;
-webkit-transition: 0.5s opacity;
-o-transition: 0.5s opacity;
-ms-transition: 0.5s opacity;
transition: 0.5s opacity;
-moz-transition: opacity 0.4s ease 0.05s;
-webkit-transition: opacity 0.4s ease 0.05s;
-o-transition: opacity 0.4s ease 0.05s;
-ms-transition: opacity 0.4s ease 0.05s;
transition: opacity 0.4s ease 0.05s;
opacity: 0;
}
.ace_fade-fold-widgets:hover .ace_fold-widget {
-moz-transition-duration: 0.05s;
-webkit-transition-duration: 0.05s;
-o-transition-duration: 0.05s;
-ms-transition-duration: 0.05s;
transition-duration: 0.05s;
-moz-transition-delay: 0.2s;
-webkit-transition-delay: 0.2s;
-o-transition-delay: 0.2s;
-ms-transition-delay: 0.2s;
transition-delay: 0.2s;
-moz-transition: opacity 0.05s ease 0.05s;
-webkit-transition: opacity 0.05s ease 0.05s;
-o-transition: opacity 0.05s ease 0.05s;
-ms-transition: opacity 0.05s ease 0.05s;
transition: opacity 0.05s ease 0.05s;
opacity:1;
}

View file

@ -326,6 +326,13 @@ var Document = function(text) {
if (lines.length == 0)
return {row: row, column: 0};
// apply doesn't work for big arrays (smallest threshold is on safari 0xFFFF)
// to circumvent that we have to break huge inserts into smaller chunks here
if (lines.length > 0xFFFF) {
var end = this.insertLines(row, lines.slice(0xFFFF));
lines = lines.slice(0, 0xFFFF);
}
var args = [row, 0];
args.push.apply(args, lines);
this.$lines.splice.apply(this.$lines, args);
@ -337,7 +344,7 @@ var Document = function(text) {
lines: lines
};
this._emit("change", { data: delta });
return range.end;
return end || range.end;
};
/**

View file

@ -51,6 +51,7 @@ var TextMode = require("./mode/text").Mode;
var Range = require("./range").Range;
var Document = require("./document").Document;
var BackgroundTokenizer = require("./background_tokenizer").BackgroundTokenizer;
var SearchHighlight = require("./search_highlight").SearchHighlight;
/**
* class EditSession
@ -307,6 +308,13 @@ var EditSession = function(text, mode) {
return token;
};
this.highlight = function(re) {
if (!this.$searchHighlight) {
var highlight = new SearchHighlight(null, "ace_selected_word", "text");
this.$searchHighlight = this.addDynamicMarker(highlight);
}
this.$searchHighlight.setRegexp(re);
}
/**
* EditSession.setUndoManager(undoManager)
* - undoManager (UndoManager): The new undo manager
@ -556,7 +564,8 @@ var EditSession = function(text, mode) {
type : type || "line",
renderer: typeof type == "function" ? type : null,
clazz : clazz,
inFront: !!inFront
inFront: !!inFront,
id: id
}
if (inFront) {
@ -570,6 +579,30 @@ var EditSession = function(text, mode) {
return id;
};
/**
* EditSession.addDynamicMarker(marker) -> {update}
* - marker : object with update method
* - inFront (Boolean): Set to `true` to establish a front marker
*
**/
this.addDynamicMarker = function(marker, inFront) {
if (!marker.update)
return;
var id = this.$markerId++;
marker.id = id;
marker.inFront = !!inFront;
if (inFront) {
this.$frontMarkers[id] = marker;
this._emit("changeFrontMarker")
} else {
this.$backMarkers[id] = marker;
this._emit("changeBackMarker")
}
return marker;
};
/**
* EditSession.removeMarker(markerId)
* - markerId (Number): A number representing a marker
@ -675,15 +708,18 @@ var EditSession = function(text, mode) {
var line = this.getLine(row);
var inToken = false;
if (column > 0) {
if (column > 0)
inToken = !!line.charAt(column - 1).match(this.tokenRe);
}
if (!inToken) {
if (!inToken)
inToken = !!line.charAt(column).match(this.tokenRe);
}
var re = inToken ? this.tokenRe : this.nonTokenRe;
if (inToken)
var re = this.tokenRe;
else if (/^\s+$/.test(line.slice(column-1, column+1)))
var re = /\s/;
else
var re = this.nonTokenRe;
var start = column;
if (start > 0) {
@ -1080,7 +1116,7 @@ var EditSession = function(text, mode) {
* {:Document.getTextRange.desc}
**/
this.getTextRange = function(range) {
return this.doc.getTextRange(range);
return this.doc.getTextRange(range || this.selection.getRange());
};
/** related to: Document.insert

View file

@ -235,6 +235,35 @@ var Editor = function(renderer, session) {
return this.session;
};
/** related to: Document.setValue
* Editor.setValue(val [,dontSelect]) -> String
* - val (String): The new value to set for the document
* - cursorPos (number): 0: selectAll, -1 document start, 1 end
*
* Sets the current document to `val`.
**/
this.setValue = function(val, cursorPos) {
this.session.doc.setValue(val);
if (!cursorPos)
this.selectAll();
else if (cursorPos == 1)
this.navigateFileEnd();
else if (cursorPos == -1)
this.navigateFileStart();
return val;
};
/** related to: EditSession.getValue
* Editor.getValue() -> String
*
* Returns the current session's content.
**/
this.getValue = function() {
return this.session.getValue();
};
/**
* Editor.getSelection() -> String
*
@ -249,8 +278,8 @@ var Editor = function(renderer, session) {
*
* {:VirtualRenderer.onResize}
**/
this.resize = function() {
this.renderer.onResize();
this.resize = function(force) {
this.renderer.onResize(force);
};
/**
@ -368,6 +397,9 @@ var Editor = function(renderer, session) {
* Emitted once the editor comes into focus.
**/
this.onFocus = function() {
if (this.$isFocused)
return;
this.$isFocused = true;
this.renderer.showCursor();
this.renderer.visualizeFocus();
this._emit("focus");
@ -379,6 +411,9 @@ var Editor = function(renderer, session) {
* Emitted once the editor has been blurred.
**/
this.onBlur = function() {
if (!this.$isFocused)
return;
this.$isFocused = false;
this.renderer.hideCursor();
this.renderer.visualizeBlur();
this._emit("blur");
@ -494,7 +529,7 @@ var Editor = function(renderer, session) {
* Emitted when a selection has changed.
**/
this.onSelectionChange = function(e) {
var session = this.getSession();
var session = this.session;
if (session.$selectionMarker) {
session.removeMarker(session.$selectionMarker);
@ -509,12 +544,40 @@ var Editor = function(renderer, session) {
this.$updateHighlightActiveLine();
}
var self = this;
if (this.$highlightSelectedWord && !this.$wordHighlightTimer)
this.$wordHighlightTimer = setTimeout(function() {
self.session.$mode.highlightSelection(self);
self.$wordHighlightTimer = null;
}, 30, this);
var re = this.$highlightSelectedWord && this.$getSelectionHighLightRegexp()
this.session.highlight(re);
};
this.$getSelectionHighLightRegexp = function() {
var session = this.session;
var selection = this.getSelectionRange();
if (selection.isEmpty() || selection.isMultiLine())
return;
var startOuter = selection.start.column - 1;
var endOuter = selection.end.column + 1;
var line = session.getLine(selection.start.row);
var lineCols = line.length;
var needle = line.substring(Math.max(startOuter, 0),
Math.min(endOuter, lineCols));
// Make sure the outer characters are not part of the word.
if ((startOuter >= 0 && /^[\w\d]/.test(needle)) ||
(endOuter <= lineCols && /[\w\d]$/.test(needle)))
return;
needle = line.substring(selection.start.column, selection.end.column);
if (!/^[\w\d]+$/.test(needle))
return;
var re = this.$search.$assembleRegExp({
wholeWord: true,
caseSensitive: true,
needle: needle
});
return re;
};
/**
@ -541,7 +604,7 @@ var Editor = function(renderer, session) {
* Emitted when a breakpoint changes.
**/
this.onChangeBreakpoint = function() {
this.renderer.setBreakpoints(this.session.getBreakpoints());
this.renderer.updateBreakpoints();
};
/**
@ -888,7 +951,7 @@ var Editor = function(renderer, session) {
this.$highlightSelectedWord = true;
/**
* Editor.setHighlightSelectedWord(shouldHighlight)
* Editor.setHighlightSelectedWord(shouldHighlight)
* - shouldHighlight (Boolean): Set to `true` to highlight the currently selected word
*
* Determines if the currently selected word should be highlighted.
@ -898,20 +961,12 @@ var Editor = function(renderer, session) {
return;
this.$highlightSelectedWord = shouldHighlight;
if (shouldHighlight) {
this.session.getMode().highlightSelection(this);
} else {
this.session.getMode().clearSelectionHighlight(this);
if (this.$wordHighlightTimer) {
clearTimeout(this.$wordHighlightTimer);
this.$wordHighlightTimer = null;
}
}
this.$onSelectionChange();
};
/**
* Editor.getHighlightSelectedWord() -> Boolean
*
*
* Returns `true` if currently highlighted words are to be highlighted.
**/
this.getHighlightSelectedWord = function() {
@ -1954,65 +2009,84 @@ var Editor = function(renderer, session) {
};
/** related to: Search.find
* Editor.find(needle, options)
* - needle (String): The text to search for
* Editor.find(needle, options)
* - needle (String): The text to search for (optional)
* - options (Object): An object defining various search properties
* - animate (Boolean): If `true` animate scrolling
*
* Attempts to find `needle` within the document. For more information on `options`, see [[Search `Search`]].
**/
this.find = function(needle, options, animate) {
this.clearSelection();
options = options || {};
options.needle = needle;
if (!options)
options = {};
if (typeof needle == "string" || needle instanceof RegExp)
options.needle = needle;
else if (typeof needle == "object")
oop.mixin(options, needle);
var range = this.selection.getRange();
if (options.needle == null) {
needle = this.session.getTextRange(range)
|| this.$search.$options.needle;
if (!needle) {
range = this.session.getWordRange(range.start.row, range.start.column);
needle = this.session.getTextRange(range);
}
this.$search.set({needle: needle});
}
this.$search.set(options);
this.$find(options.backwards, animate);
if (!options.start)
this.$search.set({start: range});
var newRange = this.$search.find(this.session);
if (options.preventScroll)
return newRange;
if (newRange) {
this.revealRange(newRange, animate);
return newRange;
}
// clear selection if nothing is found
if (options.backwards)
range.start = range.end;
else
range.end = range.start;
this.selection.setRange(range);
};
/** related to: Editor.find
* Editor.findNext(options)
* Editor.findNext(options)
* - options (Object): search options
* - animate (Boolean): If `true` animate scrolling
*
*
* Performs another search for `needle` in the document. For more information on `options`, see [[Search `Search`]].
**/
this.findNext = function(options, animate) {
options = options || {};
this.$search.set(options);
this.$find(false, animate);
this.find({skipCurrent: true, backwards: false}, options, animate);
};
/** related to: Editor.find
* Editor.findPrevious(options)
* Editor.findPrevious(options)
* - options (Object): search options
* - animate (Boolean): If `true` animate scrolling
*
*
* Performs a search for `needle` backwards. For more information on `options`, see [[Search `Search`]].
**/
this.findPrevious = function(options, animate) {
options = options || {};
this.$search.set(options);
this.$find(true, animate);
this.find(options, {skipCurrent: true, backwards: true}, animate);
};
this.$find = function(backwards, animate) {
if (!this.selection.isEmpty())
this.$search.set({needle: this.session.getTextRange(this.getSelectionRange())});
this.revealRange = function(range, animate) {
this.$blockScrolling += 1;
this.session.unfold(range);
this.selection.setSelectionRange(range);
this.$blockScrolling -= 1;
if (typeof backwards != "undefined")
this.$search.set({backwards: backwards});
var range = this.$search.find(this.session);
if (range) {
this.$blockScrolling += 1;
this.session.unfold(range);
this.selection.setSelectionRange(range);
this.$blockScrolling -= 1;
var scrollTop = this.renderer.scrollTop;
this.renderer.scrollSelectionIntoView(range.start, range.end, 0.5);
var scrollTop = this.renderer.scrollTop;
this.renderer.scrollSelectionIntoView(range.start, range.end, 0.5);
if (animate != false)
this.renderer.animateScrolling(scrollTop);
}
};
/** related to: UndoManager.undo

View file

@ -70,6 +70,16 @@ var lipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
"libero vehicula odio, eget bibendum mauris velit eu lorem.\n" +
"consectetur";
function callHighlighterUpdate(session, firstRow, lastRow) {
var rangeCount = 0;
var mockMarkerLayer = { drawSingleLineMarker: function() {rangeCount++;} }
session.$searchHighlight.update([], mockMarkerLayer, session, {
firstRow: firstRow,
lastRow: lastRow
});
return rangeCount;
}
module.exports = {
setUp: function(next) {
this.session = new EditSession(lipsum);
@ -87,55 +97,51 @@ module.exports = {
this.editor.moveCursorTo(0, 9);
this.selection.selectWord();
assert.ok(this.editor.$wordHighlightTimer != null);
this.session.$mode.highlightSelection(this.editor);
var highlighter = this.editor.session.$searchHighlight;
assert.ok(highlighter != null);
var range = this.selection.getRange();
assert.equal(this.session.getTextRange(range), "ipsum");
assert.equal(this.session.$selectionOccurrences.length, 1);
assert.equal(highlighter.cache.length, 0);
assert.equal(callHighlighterUpdate(this.session, 0, 0), 2);
},
"test: highlight a word and clear highlight": function() {
this.editor.moveCursorTo(0, 8);
this.selection.selectWord();
this.session.$mode.highlightSelection(this.editor);
var range = this.selection.getRange();
assert.equal(this.session.getTextRange(range), "ipsum");
assert.equal(this.session.$selectionOccurrences.length, 1);
assert.equal(callHighlighterUpdate(this.session, 0, 0), 2);
this.session.getMode().clearSelectionHighlight(this.editor);
assert.equal(this.session.$selectionOccurrences.length, 0);
this.session.highlight("");
assert.equal(this.session.$searchHighlight.cache.length, 0);
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
},
"test: highlight another word": function() {
this.selection.moveCursorTo(0, 14);
this.selection.selectWord();
this.session.$mode.highlightSelection(this.editor);
var range = this.selection.getRange();
assert.equal(this.session.getTextRange(range), "dolor");
assert.equal(this.session.$selectionOccurrences.length, 3);
assert.equal(callHighlighterUpdate(this.session, 0, 0), 4);
},
"test: no selection, no highlight": function() {
this.selection.clearSelection();
this.session.$mode.highlightSelection(this.editor);
assert.equal(this.session.$selectionOccurrences.length, 0);
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
},
"test: select a word, no highlight": function() {
this.selection.moveCursorTo(0, 14);
this.selection.selectWord();
this.session.$mode.highlightSelection(this.editor);
this.editor.setHighlightSelectedWord(false);
assert.ok(this.editor.$wordHighlightTimer == null);
var range = this.selection.getRange();
assert.equal(this.session.getTextRange(range), "dolor");
assert.equal(this.session.$selectionOccurrences.length, 0);
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
},
"test: select a word with no matches": function() {
@ -156,32 +162,29 @@ module.exports = {
this.search.set(currentOptions);
this.selection.setSelectionRange(match);
this.session.$mode.highlightSelection(this.editor);
assert.equal(this.session.getTextRange(match), "Mauris");
assert.equal(this.session.$selectionOccurrences.length, 0);
assert.equal(callHighlighterUpdate(this.session, 0, 0), 1);
},
"test: partial word selection 1": function() {
this.selection.moveCursorTo(0, 14);
this.selection.selectWord();
this.selection.selectLeft();
this.session.$mode.highlightSelection(this.editor);
var range = this.selection.getRange();
assert.equal(this.session.getTextRange(range), "dolo");
assert.equal(this.session.$selectionOccurrences.length, 0);
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
},
"test: partial word selection 2": function() {
this.selection.moveCursorTo(0, 13);
this.selection.selectWord();
this.selection.selectRight();
this.session.$mode.highlightSelection(this.editor);
var range = this.selection.getRange();
assert.equal(this.session.getTextRange(range), "dolor ");
assert.equal(this.session.$selectionOccurrences.length, 0);
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
},
"test: partial word selection 3": function() {
@ -189,11 +192,10 @@ module.exports = {
this.selection.selectWord();
this.selection.selectLeft();
this.selection.shiftSelection(1);
this.session.$mode.highlightSelection(this.editor);
var range = this.selection.getRange();
assert.equal(this.session.getTextRange(range), "olor");
assert.equal(this.session.$selectionOccurrences.length, 0);
assert.equal(callHighlighterUpdate(this.session, 0, 0), 0);
},
"test: select last word": function() {
@ -216,10 +218,9 @@ module.exports = {
this.search.set(currentOptions);
this.selection.setSelectionRange(match);
this.session.$mode.highlightSelection(this.editor);
assert.equal(this.session.getTextRange(match), "consectetur");
assert.equal(this.session.$selectionOccurrences.length, 2);
assert.equal(callHighlighterUpdate(this.session, 0, 1), 3);
}
};

View file

@ -57,9 +57,8 @@ function HashHandler(config, platform) {
this.commands[command.name] = command;
if (command.bindKey) {
if (command.bindKey)
this._buildKeyHash(command);
}
};
this.removeCommand = function(command) {
@ -81,6 +80,10 @@ function HashHandler(config, platform) {
this.bindKey = function(key, command) {
if(!key)
return;
if (typeof command == "function") {
this.addCommand({exec: command, bindKey: key, name: key});
return;
}
var ckb = this.commmandKeyBinding;
key.split("|").forEach(function(keyPart) {

View file

@ -119,7 +119,8 @@ var KeyBinding = function(editor) {
else
success = toExecute.passEvent != true;
if (success && e)
// do not stop input events to not break repeating
if (success && e && hashId != -1)
event.stopEvent(e);
return success;

View file

@ -45,18 +45,22 @@ var useragent = require("../lib/useragent");
var dom = require("../lib/dom");
var TextInput = function(parentNode, host) {
var text = dom.createElement("textarea");
/*/ debug
text.style.opacity = 1
text.style.background = "rgba(0, 250, 0, 0.3)"
text.style.outline = "rgba(0, 250, 0, 0.8) solid 1px"
text.style.outlineOffset = "3px"
/**/
if (useragent.isTouchPad)
text.setAttribute("x-palm-disable-auto-cap", true);
text.setAttribute("wrap", "off");
text.style.left = "-10000px";
text.style.position = "fixed";
text.style.top = "-2em";
parentNode.insertBefore(text, parentNode.firstChild);
var PLACEHOLDER = String.fromCharCode(0);
var PLACEHOLDER = useragent.isIE ? "\x01" : "\x01";
sendText();
var inCompostion = false;
@ -64,9 +68,14 @@ var TextInput = function(parentNode, host) {
var pasted = false;
var tempStyle = '';
function select() {
function reset(full) {
try {
text.select();
if (full) {
text.value = PLACEHOLDER;
text.selectionStart = 0;
text.selectionEnd = 1;
} else
text.select();
} catch (e) {}
}
@ -87,11 +96,6 @@ var TextInput = function(parentNode, host) {
else
host.onTextInput(value);
}
// If editor is no longer focused we quit immediately, since
// it means that something else is in charge now.
if (!isFocused())
return false;
}
}
@ -99,19 +103,19 @@ var TextInput = function(parentNode, host) {
pasted = false;
// Safari doesn't fire copy events if no text is selected
text.value = PLACEHOLDER;
select();
reset(true);
}
var onTextInput = function(e) {
if (!inCompostion)
sendText(e.data);
setTimeout(function () {
if (!inCompostion)
sendText(e.data);
reset(true);
}, 0);
};
var onPropertyChange = function(e) {
if (useragent.isOldIE && text.value.charCodeAt(0) > 128) return;
setTimeout(function() {
if (!inCompostion)
sendText();
@ -121,7 +125,7 @@ var TextInput = function(parentNode, host) {
var onCompositionStart = function(e) {
inCompostion = true;
host.onCompositionStart();
if (!useragent.isGecko) setTimeout(onCompositionUpdate, 0);
setTimeout(onCompositionUpdate, 0);
};
var onCompositionUpdate = function() {
@ -141,12 +145,12 @@ var TextInput = function(parentNode, host) {
text.value = copyText;
else
e.preventDefault();
select();
reset();
setTimeout(function () {
sendText();
}, 0);
};
var onCut = function(e) {
copied = true;
var copyText = host.getCopyText();
@ -155,31 +159,15 @@ var TextInput = function(parentNode, host) {
host.onCut();
} else
e.preventDefault();
select();
reset();
setTimeout(function () {
sendText();
}, 0);
};
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
event.addListener(text, "input", useragent.isIE ? onPropertyChange : onTextInput);
if (useragent.isOldIE) {
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();
});
}
if ("onpropertychange" in text && !("oninput" in text))
event.addListener(text, "propertychange", onPropertyChange);
else
event.addListener(text, "input", onTextInput);
event.addListener(text, "paste", function(e) {
// Mark that the next input text comes from past.
pasted = true;
@ -198,6 +186,8 @@ var TextInput = function(parentNode, host) {
if ("onbeforecopy" in text && typeof clipboardData !== "undefined") {
event.addListener(text, "beforecopy", function(e) {
if (tempStyle)
return; // without this text is copied when contextmenu is shown
var copyText = host.getCopyText();
if (copyText)
clipboardData.setData("Text", copyText);
@ -214,6 +204,7 @@ var TextInput = function(parentNode, host) {
event.preventDefault(e);
}
});
event.addListener(text, "cut", onCut); // for ie9 context menu
}
else if (useragent.isOpera) {
event.addListener(parentNode, "keydown", function(e) {
@ -251,12 +242,12 @@ var TextInput = function(parentNode, host) {
event.addListener(text, "focus", function() {
host.onFocus();
select();
reset();
});
this.focus = function() {
host.onFocus();
select();
reset();
text.focus();
};
@ -273,28 +264,50 @@ var TextInput = function(parentNode, host) {
return text;
};
this.onContextMenu = function(mousePos, isEmpty){
if (mousePos) {
if (!tempStyle)
tempStyle = text.style.cssText;
text.style.cssText =
'position:fixed; z-index:1000;' +
'left:' + (mousePos.x - 2) + 'px; top:' + (mousePos.y - 2) + 'px;';
}
if (isEmpty)
text.value='';
this.onContextMenu = function(e) {
if (!tempStyle)
tempStyle = text.style.cssText;
text.style.cssText =
"position:fixed; z-index:100000;" + //"background:rgba(250, 0, 0, 0.3); opacity:1;" +
"left:" + (e.clientX - 2) + "px; top:" + (e.clientY - 2) + "px;";
if (host.selection.isEmpty())
text.value = "";
if (e.type != "mousedown")
return;
if (host.renderer.$keepTextAreaAtCursor)
host.renderer.$keepTextAreaAtCursor = null;
event.capture(host.container, function(e) {
text.style.left = e.clientX - 2 + "px";
text.style.top = e.clientY - 2 + "px";
}, onContextMenuClose);
};
this.onContextMenuClose = function(){
function onContextMenuClose() {
setTimeout(function () {
if (tempStyle) {
text.style.cssText = tempStyle;
tempStyle = '';
}
sendText();
if (host.renderer.$keepTextAreaAtCursor == null) {
host.renderer.$keepTextAreaAtCursor = true;
host.renderer.$moveTextAreaToCursor();
}
}, 0);
};
this.onContextMenuClose = onContextMenuClose;
// firefox fires contextmenu event after opening it
if (!useragent.isGecko)
event.addListener(text, "contextmenu", function(e) {
host.textInput.onContextMenu(e);
onContextMenuClose()
});
};
exports.TextInput = TextInput;

View file

@ -108,7 +108,9 @@ exports.handler = {
editor.removeListener("click", exports.onCursorMove);
util.noMode(editor);
util.currentMode = "normal";
}
},
actions: cmds.actions
};

View file

@ -52,18 +52,6 @@ var MOTION = 3;
var ACTION = 4;
var HMARGIN = 8; // Minimum amount of line separation between margins;
exports.searchStore = {
current: "",
options: {
needle: "",
backwards: false,
wrap: true,
caseSensitive: false,
wholeWord: false,
regExp: false
}
};
var repeat = function repeat(fn, count, args) {
while (0 < count--)
fn.apply(this, args);
@ -88,7 +76,7 @@ var ensureScrollMargin = function(editor) {
}
};
var actions = {
var actions = exports.actions = {
"z": {
param: true,
fn: function(editor, range, count, param) {
@ -288,16 +276,17 @@ var actions = {
},
":": {
fn: function(editor, range, count, param) {
editor.blur();
txtConsoleInput.focus();
txtConsoleInput.setValue(":");
// not implemented
}
},
"/": {
fn: function(editor, range, count, param) {
editor.blur();
txtConsoleInput.focus();
txtConsoleInput.setValue("/");
// not implemented
}
},
"?": {
fn: function(editor, range, count, param) {
// not implemented
}
},
".": {

View file

@ -72,11 +72,7 @@ var Gutter = function(parentEl) {
};
this.removeGutterDecoration = function(row, className){
this.$decorations[row] = this.$decorations[row].replace(" " + className, "");
};
this.setBreakpoints = function(rows) {
this.$breakpoints = rows.concat();
this.$decorations[row] = (this.$decorations[row] || "").replace(" " + className, "");
};
this.setAnnotations = function(annotations) {
@ -116,6 +112,7 @@ var Gutter = function(parentEl) {
var fold = this.session.getNextFoldLine(i);
var foldStart = fold ? fold.start.row : Infinity;
var foldWidgets = this.$showFoldWidgets && this.session.foldWidgets;
var breakpoints = this.session.$breakpoints;
while (true) {
if(i > foldStart) {
@ -129,10 +126,10 @@ var Gutter = function(parentEl) {
var annotation = this.$annotations[i] || emptyAnno;
html.push("<div class='ace_gutter-cell",
this.$decorations[i] || "",
this.$breakpoints[i] ? " ace_breakpoint " : " ",
breakpoints[i] ? " ace_breakpoint " : " ",
annotation.className,
"' title='", annotation.text.join("\n"),
"' style='height:", config.lineHeight, "px;'>", (i+1));
"' style='height:", this.session.getRowLength(i) * config.lineHeight, "px;'>", (i+1));
if (foldWidgets) {
var c = foldWidgets[i];
@ -147,15 +144,18 @@ var Gutter = function(parentEl) {
);
}
var wrappedRowLength = this.session.getRowLength(i) - 1;
while (wrappedRowLength--) {
html.push("</div><div class='ace_gutter-cell' style='height:", config.lineHeight, "px'>\xA6");
}
html.push("</div>");
i++;
}
if (this.session.$useWrapMode)
html.push(
"<div class='ace_gutter-cell' style='pointer-events:none;opacity:0'>",
this.session.getLength() - 1,
"</div>"
);
this.element = dom.setInnerHtml(this.element, html.join(""));
this.element.style.height = config.minHeight + "px";

View file

@ -76,6 +76,11 @@ var Marker = function(parentEl) {
for ( var key in this.markers) {
var marker = this.markers[key];
if (!marker.range) {
marker.update(html, this, this.session, config);
continue;
}
var range = marker.range.clipRows(config.firstRow, config.lastRow);
if (range.isEmpty()) continue;

View file

@ -184,32 +184,41 @@ exports.addMouseWheelListener = function(el, callback) {
exports.addListener(el, "mousewheel", listener);
};
exports.addMultiMouseDownListener = function(el, button, count, timeout, callback) {
exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbackName) {
var clicks = 0;
var startX, startY;
var startX, startY, timer;
var eventNames = {
2: "dblclick",
3: "tripleclick",
4: "quadclick"
};
var listener = function(e) {
clicks += 1;
if (exports.getButton(e) != 0) {
clicks = 0;
} else {
var isNewClick = Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5;
if (!timer || isNewClick)
clicks = 0;
clicks += 1;
if (timer)
clearTimeout(timer)
timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600);
}
if (clicks == 1) {
startX = e.clientX;
startY = e.clientY;
setTimeout(function() {
clicks = 0;
}, timeout || 600);
}
var isButton = exports.getButton(e) == button;
if (!isButton || Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5)
clicks = 0;
eventHandler[callbackName]("mousedown", e);
if (clicks == count) {
if (clicks > 4)
clicks = 0;
callback(e);
}
if (isButton)
return exports.preventDefault(e);
else if (clicks > 1)
return eventHandler[callbackName](eventNames[clicks], e);
};
exports.addListener(el, "mousedown", listener);

View file

@ -116,6 +116,20 @@ exports.escapeRegExp = function(str) {
return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
};
exports.getMatchOffsets = function(string, regExp) {
var matches = [];
string.replace(regExp, function(str) {
matches.push({
offset: arguments[arguments.length-2],
length: str.length
});
});
return matches;
};
exports.deferredCall = function(fcn) {
var timer = null;

View file

@ -47,13 +47,13 @@ var C9SearchHighlightRules = function() {
// regexps are ordered -> the first match is used
this.$rules = {
"start" : [
{
token : ["constant.numeric", "text", "text"],
regex : "(^\\s+[0-9]+)(:\\s*)(.+)"
},
{
token : ["string", "text"], // single line
regex : "(.+)(:$)"
},
{
token : ["constant.numeric", "text"],
regex : "(^\\s*[0-9]+)(:\\s*)"
}
]
};

View file

@ -191,6 +191,10 @@ var ClojureHighlightRules = function() {
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // multi line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?$',
next: "string"
}, {
token : "string", // symbol
regex : "[:](?:[a-zA-Z]|\\d)+"
@ -210,6 +214,17 @@ var ClojureHighlightRules = function() {
merge : true,
regex : ".+"
}
],
"string" : [
{
token : "string",
merge : true,
regex : "\\\\."
}, {
token : "string",
regex : '[^"\\\\]*?"',
next : "start"
}
]
};
};

View file

@ -26,7 +26,7 @@ var CSharpHighlightRules = function() {
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
DocCommentHighlightRules.getStartRule("doc-start"),
{
token : "comment", // multi line comment
regex : "\\/\\*",
@ -95,7 +95,7 @@ var CSharpHighlightRules = function() {
};
this.embedRules(DocCommentHighlightRules, "doc-",
[ new DocCommentHighlightRules().getEndRule("start") ]);
[ DocCommentHighlightRules.getEndRule("start") ]);
};
oop.inherits(CSharpHighlightRules, TextHighlightRules);

58
lib/ace/mode/diff.js Normal file
View file

@ -0,0 +1,58 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var TextMode = require("./text").Mode;
var Tokenizer = require("../tokenizer").Tokenizer;
var HighlightRules = require("./diff_highlight_rules").DiffHighlightRules;
var FoldMode = require("./folding/diff").FoldMode;
var Mode = function() {
this.$tokenizer = new Tokenizer(new HighlightRules().getRules(), "i");
this.foldingRules = new FoldMode(["diff", "index", "\\+{3}", "@@|\\*{5}"], "i");
};
oop.inherits(Mode, TextMode);
(function() {
}).call(Mode.prototype);
exports.Mode = Mode;
});

View file

@ -0,0 +1,108 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var DiffHighlightRules = function() {
// regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used
this.$rules = {
"start" : [{
"regex": "^(?:\\*{15}|={67}|-{3}|\\+{3})$",
"token": "punctuation.definition.separator.diff",
"name": "keyword"
}, { //diff.range.unified
"regex": "^(@@)(\\s*.+?\\s*)(@@)(.*)$",
"token": [
"constant",
"constant.numeric",
"constant",
"comment.doc.tag"
]
}, { //diff.range.normal
"regex": "^(\\d+)([,\\d]+)(a|d|c)(\\d+)([,\\d]+)(.*)$",
"token": [
"constant.numeric",
"punctuation.definition.range.diff",
"constant.function",
"constant.numeric",
"punctuation.definition.range.diff",
"invalid"
],
"name": "meta."
}, {
"regex": "^(?:(\\-{3}|\\+{3}|\\*{3})( .+))$",
"token": [
"constant.numeric",
"meta.tag"
]
}, { // added
"regex": "^([!+>])(.*?)(\\s*)$",
"token": [
"support.constant",
"text",
"invalid"
],
}, { // removed
"regex": "^([<\\-])(.*?)(\\s*)$",
"token": [
"support.function",
"string",
"invalid"
],
}, {
"regex": "^(diff)(\\s+--\\w+)?(.+?)( .+)?$",
"token": ["variable", "variable", "keyword", "variable"]
}, {
"regex": "^Index.+$",
"token": "variable"
}, {
"regex": "^(.*?)(\\s*)$",
"token": ["invisible", "invalid"]
}
]
};
};
oop.inherits(DiffHighlightRules, TextHighlightRules);
exports.DiffHighlightRules = DiffHighlightRules;
});

View file

@ -0,0 +1,76 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* 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
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("../../lib/oop");
var BaseFoldMode = require("./fold_mode").FoldMode;
var Range = require("../../range").Range;
var FoldMode = exports.FoldMode = function(levels, flag) {
this.regExpList = levels;
this.flag = flag;
this.foldingStartMarker = RegExp("^(" + levels.join("|") + ")", this.flag);
};
oop.inherits(FoldMode, BaseFoldMode);
(function() {
this.getFoldWidgetRange = function(session, foldStyle, row) {
var line = session.getLine(row);
var start = {row: row, column: line.length};
var regList = this.regExpList;
for (var i = 1; i <= regList.length; i++) {
var re = RegExp("^(" + regList.slice(0, i).join("|") + ")", this.flag);
if (re.test(line))
break;
}
for (var l = session.getLength(); ++row < l; ) {
line = session.getLine(row);
if (re.test(line))
break
}
if (row == start.row + 1)
return;
return Range.fromPoints(start, {row: row - 1, column: line.length});
};
}).call(FoldMode.prototype);
});

View file

@ -5,10 +5,13 @@ define(function(require, exports, module) {
var Tokenizer = require("../tokenizer").Tokenizer;
var GolangHighlightRules = require("./golang_highlight_rules").GolangHighlightRules;
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour;
var CStyleFoldMode = require("./folding/cstyle").FoldMode;
var Mode = function() {
this.$tokenizer = new Tokenizer(new GolangHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
this.foldingRules = new CStyleFoldMode();
};
oop.inherits(Mode, TextMode);

View file

@ -119,6 +119,9 @@ define(function(require, exports, module) {
}
]
};
this.embedRules(DocCommentHighlightRules, "doc-",
[ DocCommentHighlightRules.getEndRule("start") ]);
}
oop.inherits(GolangHighlightRules, TextHighlightRules);

View file

@ -73,6 +73,14 @@ var GroovyHighlightRules = function() {
}, {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string",
regex : '"""',
next : "qqstring"
}, {
token : "string",
regex : "'''",
next : "qstring"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
@ -130,6 +138,38 @@ var GroovyHighlightRules = function() {
merge : true,
regex : ".+"
}
],
"qqstring" : [
{
token : "constant.language.escape",
regex : /\\(?:u[0-9A-Fa-f]{4}|.|$)/
}, {
token : "constant.language.escape",
regex : /\$[\w\d]+/
}, {
token : "constant.language.escape",
regex : /\$\{[^"\}]+\}?/
}, {
token : "string",
regex : '"{3,5}',
next : "start"
}, {
token : "string",
regex : '.+?'
}
],
"qstring" : [
{
token : "constant.language.escape",
regex : /\\(?:u[0-9A-Fa-f]{4}|.|$)/
}, {
token : "string",
regex : "'{3,5}",
next : "start"
}, {
token : "string",
regex : ".+?"
}
]
};

View file

@ -49,8 +49,12 @@ var JsonHighlightRules = function() {
this.$rules = {
"start" : [
{
token : "variable", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)'
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
regex : '"',
next : "string"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
@ -76,6 +80,26 @@ var JsonHighlightRules = function() {
token : "text",
regex : "\\s+"
}
],
"string" : [
{
token : "constant.language.escape",
regex : /\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})/
}, {
token : "string",
regex : '[^"\\\\]+',
merge : true
}, {
token : "string",
regex : '"',
next : "start",
merge : true
}, {
token : "string",
regex : "",
next : "start",
merge : true
}
]
};

View file

@ -948,18 +948,12 @@ var PhpHighlightRules = function() {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/][gimy]*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // multi line string start
regex : '["][\\s\\S]*',
token : "string", // " string start
regex : '"',
next : "qqstring"
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "string", // multi line string start
regex : "['][\\s\\S]+",
token : "string", // ' string start
regex : "'",
next : "qstring"
}, {
token : "constant.numeric", // hex
@ -1040,33 +1034,45 @@ var PhpHighlightRules = function() {
],
"qqstring" : [
{
token : "constant.language.escape",
regex : '\\\\(?:[nrtvef\\\\"$]|[0-7]{1,3}|x[0-9A-Fa-f]{1,2})'
}, {
token : "constant.language.escape",
regex : /\$[\w\d]+(?:\[[\w\d]+\])?/
}, {
token : "constant.language.escape",
regex : /\$\{[^"\}]+\}?/ // this is wrong but ok for now
}, {
token : "string",
regex : '"',
next : "start"
}, {
token : "string",
regex : '[^"]+'
regex : '.+?'
}
],
"qstring" : [
{
token : "constant.language.escape",
regex : "\\\\['\\\\]"
}, {
token : "string",
regex : "'",
next : "start"
}, {
token : "string",
regex : "[^']+"
regex : ".+?"
}
],
"htmlcomment" : [
{
token : "comment",
regex : ".*?-->",
next : "start"
}, {
token : "comment",
regex : ".+"
}
{
token : "comment",
regex : ".*?-->",
next : "start"
}, {
token : "comment",
regex : ".+"
}
],
"htmltag" : [
{

View file

@ -75,11 +75,16 @@ var ScalaHighlightRules = function() {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
token : "string",
regex : '"""',
next : "tstring"
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
token : "string",
regex : '"(?=.)', // " strings can't span multiple lines
next : "string"
}, {
token : "symbol.constant", // single line
regex : "'[\\w\\d_]+"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
@ -131,6 +136,36 @@ var ScalaHighlightRules = function() {
merge : true,
regex : ".+"
}
],
"string" : [
{
token : "escape",
regex : '\\\\"',
}, {
token : "string",
merge : true,
regex : '"',
next : "start"
}, {
token : "string.invalid",
regex : '[^"\\\\]*$',
next : "start"
}, {
token : "string",
regex : '[^"\\\\]+',
merge : true
}
],
"tstring" : [
{
token : "string", // closing comment
regex : '"{3,5}',
next : "start"
}, {
token : "string", // comment spanning whole line
merge : true,
regex : ".+?"
}
]
};

View file

@ -98,68 +98,6 @@ var Mode = function() {
return null;
};
this.highlightSelection = function(editor) {
var session = editor.session;
if (!session.$selectionOccurrences)
session.$selectionOccurrences = [];
if (session.$selectionOccurrences.length)
this.clearSelectionHighlight(editor);
var selection = editor.getSelectionRange();
if (selection.isEmpty() || selection.isMultiLine())
return;
var startOuter = selection.start.column - 1;
var endOuter = selection.end.column + 1;
var line = session.getLine(selection.start.row);
var lineCols = line.length;
var needle = line.substring(Math.max(startOuter, 0),
Math.min(endOuter, lineCols));
// Make sure the outer characters are not part of the word.
if ((startOuter >= 0 && /^[\w\d]/.test(needle)) ||
(endOuter <= lineCols && /[\w\d]$/.test(needle)))
return;
needle = line.substring(selection.start.column, selection.end.column);
if (!/^[\w\d]+$/.test(needle))
return;
var cursor = editor.getCursorPosition();
var newOptions = {
wrap: true,
wholeWord: true,
caseSensitive: true,
needle: needle
};
var currentOptions = editor.$search.getOptions();
editor.$search.set(newOptions);
var ranges = editor.$search.findAll(session);
ranges.forEach(function(range) {
if (!range.contains(cursor.row, cursor.column)) {
var marker = session.addMarker(range, "ace_selected_word", "text");
session.$selectionOccurrences.push(marker);
}
});
editor.$search.set(currentOptions);
};
this.clearSelectionHighlight = function(editor) {
if (!editor.session.$selectionOccurrences)
return;
editor.session.$selectionOccurrences.forEach(function(marker) {
editor.session.removeMarker(marker);
});
editor.session.$selectionOccurrences = [];
};
this.createModeDelegates = function (mapping) {
if (!this.$embeds) {
return;

View file

@ -67,6 +67,7 @@ function GutterHandler(mouseHandler) {
}
mouseHandler.captureMouse(e, "selectByLines");
return e.preventDefault();
});
}

View file

@ -42,16 +42,12 @@ define(function(require, exports, module) {
"use strict";
var dom = require("../lib/dom");
var BrowserFocus = require("../lib/browser_focus").BrowserFocus;
var useragent = require("../lib/useragent");
var DRAG_OFFSET = 5; // pixels
function DefaultHandlers(mouseHandler) {
mouseHandler.$clickSelection = null;
mouseHandler.browserFocus = new BrowserFocus();
var editor = mouseHandler.editor;
editor.setDefaultHandler("mousedown", this.onMouseDown.bind(mouseHandler));
@ -61,7 +57,7 @@ function DefaultHandlers(mouseHandler) {
editor.setDefaultHandler("mousewheel", this.onScroll.bind(mouseHandler));
var exports = ["select", "startSelect", "drag", "dragEnd", "dragWait",
"dragWaitEnd", "startDrag"];
"dragWaitEnd", "startDrag", "focusWait"];
exports.forEach(function(x) {
mouseHandler[x] = this[x];
@ -69,44 +65,43 @@ function DefaultHandlers(mouseHandler) {
mouseHandler.selectByLines = this.extendSelectionBy.bind(mouseHandler, "getLineRange");
mouseHandler.selectByWords = this.extendSelectionBy.bind(mouseHandler, "getWordRange");
mouseHandler.$focusWaitTimout = 250;
}
(function() {
this.onMouseDown = function(ev) {
this.mousedownEvent = ev;
var inSelection = ev.inSelection();
var pos = ev.getDocumentPosition();
this.mousedownEvent = ev;
var editor = this.editor;
var _self = this;
this.ev = ev
var selectionRange = editor.getSelectionRange();
var selectionEmpty = selectionRange.isEmpty();
var button = ev.getButton();
if (button !== 0) {
var selectionRange = editor.getSelectionRange();
var selectionEmpty = selectionRange.isEmpty();
if (selectionEmpty) {
editor.moveCursorToPosition(pos);
editor.selection.clearSelection();
}
// 2: contextmenu, 1: linux paste
this.moveTextarea = function() {
editor.textInput.onContextMenu({x: _self.x, y: _self.y});
};
this.moveTextareaEnd = editor.textInput.onContextMenuClose;
editor.textInput.onContextMenu({x: this.x, y: this.y}, selectionEmpty);
this.captureMouse(ev, "moveTextarea");
return;
// 2: contextmenu, 1: linux paste
editor.textInput.onContextMenu(ev.domEvent);
return ev.stop();
}
// if this click caused the editor to be focused should not clear the
// selection
if (inSelection && !editor.isFocused()) {
editor.focus();
return;
if (this.$focusWaitTimout && !this.$clickSelection) {
this.setState("focusWait");
this.captureMouse(ev);
return ev.preventDefault();
}
}
if (!inSelection || this.$clickSelection || ev.getShiftKey()) {
@ -123,7 +118,8 @@ function DefaultHandlers(mouseHandler) {
}
}
this.captureMouse(ev)
this.captureMouse(ev);
return ev.preventDefault();
};
this.startSelect = function(pos) {
@ -217,6 +213,14 @@ function DefaultHandlers(mouseHandler) {
editor.keyBinding.addKeyboardHandler(this.$dragKeybinding);
};
this.focusWait = function() {
var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y);
var time = (new Date()).getTime();
if (distance > DRAG_OFFSET ||time - this.mousedownEvent.time > this.$focusWaitTimout)
this.startSelect();
};
this.dragWait = function() {
var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y);
var time = (new Date()).getTime();
@ -224,7 +228,7 @@ function DefaultHandlers(mouseHandler) {
if (distance > DRAG_OFFSET) {
this.startSelect();
} else if ((time - this.mousedownEvent.time) > editor.getDragDelay()) {
} else if (time - this.mousedownEvent.time > editor.getDragDelay()) {
this.startDrag()
}
};

View file

@ -0,0 +1,105 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var event = require("../lib/event");
var DragdropHandler = function(mouseHandler) {
var editor = mouseHandler.editor;
var dragSelectionMarker, x, y;
var timerId, range, isBackwards;
var dragCursor, counter = 0;
var mouseTarget = editor.container;
event.addListener(mouseTarget, "dragenter", function(e) {console.log(e.type, counter,e.target);
counter++;
if (!dragSelectionMarker) {
range = editor.getSelectionRange();
isBackwards = editor.selection.isBackwards();
var style = editor.getSelectionStyle();
dragSelectionMarker = editor.session.addMarker(range, "ace_selection", style);
editor.clearSelection();
clearInterval(timerId);
timerId = setInterval(onDragInterval, 20);
}
return event.preventDefault(e);
});
event.addListener(mouseTarget, "dragover", function(e) {
x = e.clientX;
y = e.clientY;
return event.preventDefault(e);
});
var onDragInterval = function() {
dragCursor = editor.renderer.screenToTextCoordinates(x, y);
editor.moveCursorToPosition(dragCursor);
editor.renderer.scrollCursorIntoView();
};
event.addListener(mouseTarget, "dragleave", function(e) {console.log(e.type, counter,e.target);
counter--;
if (counter > 0)
return;
console.log(e.type, counter,e.target);
clearInterval(timerId);
editor.session.removeMarker(dragSelectionMarker);
dragSelectionMarker = null;
editor.selection.setSelectionRange(range, isBackwards);
return event.preventDefault(e);
});
event.addListener(mouseTarget, "drop", function(e) {
console.log(e.type, counter,e.target);
counter = 0;
clearInterval(timerId);
editor.session.removeMarker(dragSelectionMarker);
dragSelectionMarker = null;
range.end = editor.session.insert(dragCursor, e.dataTransfer.getData('Text'));
range.start = dragCursor;
editor.focus();
editor.selection.setSelectionRange(range);
return event.preventDefault(e);
});
};
exports.DragdropHandler = DragdropHandler;
});

View file

@ -44,28 +44,24 @@ var event = require("../lib/event");
var DefaultHandlers = require("./default_handlers").DefaultHandlers;
var DefaultGutterHandler = require("./default_gutter_handler").GutterHandler;
var MouseEvent = require("./mouse_event").MouseEvent;
var DragdropHandler = require("./dragdrop").DragdropHandler;
var MouseHandler = function(editor) {
this.editor = editor;
new DefaultHandlers(this);
new DefaultGutterHandler(this);
new DragdropHandler(this);
event.addListener(editor.container, "mousedown", function(e) {
editor.focus();
return event.preventDefault(e);
});
event.addListener(editor.container, "selectstart", function(e) {
return event.preventDefault(e);
});
var mouseTarget = editor.renderer.getMouseEventTarget();
event.addListener(mouseTarget, "mousedown", this.onMouseEvent.bind(this, "mousedown"));
event.addListener(mouseTarget, "click", this.onMouseEvent.bind(this, "click"));
event.addListener(mouseTarget, "mousemove", this.onMouseMove.bind(this, "mousemove"));
event.addMultiMouseDownListener(mouseTarget, 0, 2, 500, this.onMouseEvent.bind(this, "dblclick"));
event.addMultiMouseDownListener(mouseTarget, 0, 3, 600, this.onMouseEvent.bind(this, "tripleclick"));
event.addMultiMouseDownListener(mouseTarget, 0, 4, 600, this.onMouseEvent.bind(this, "quadclick"));
event.addMultiMouseDownListener(mouseTarget, [300, 300, 250], this, "onMouseEvent");
event.addMouseWheelListener(editor.container, this.onMouseWheel.bind(this, "mousewheel"));
var gutterEl = editor.renderer.$gutter;
@ -129,8 +125,9 @@ var MouseHandler = function(editor) {
this.y = ev.y;
// do not move textarea during selection
var kt = this.editor.renderer.$keepTextAreaAtCursor;
this.editor.renderer.$keepTextAreaAtCursor = false;
var renderer = this.editor.renderer;
if (renderer.$keepTextAreaAtCursor)
renderer.$keepTextAreaAtCursor = null;
var self = this;
var onMouseSelection = function(e) {
@ -142,8 +139,10 @@ var MouseHandler = function(editor) {
clearInterval(timerId);
self[self.state + "End"] && self[self.state + "End"](e);
self.$clickSelection = null;
self.editor.renderer.$keepTextAreaAtCursor = kt;
self.editor.renderer.$moveTextAreaToCursor();
if (renderer.$keepTextAreaAtCursor == null) {
renderer.$keepTextAreaAtCursor = true;
renderer.$moveTextAreaToCursor();
}
};
var onSelectionInterval = function() {
@ -152,8 +151,6 @@ var MouseHandler = function(editor) {
event.capture(this.editor.container, onMouseSelection, onMouseSelectionEnd);
var timerId = setInterval(onSelectionInterval, 20);
ev.preventDefault();
};
}).call(MouseHandler.prototype);

View file

@ -43,7 +43,8 @@ var Range = require("./range").Range;
var Selection = require("./selection").Selection;
var onMouseDown = require("./mouse/multi_select_handler").onMouseDown;
var event = require("./lib/event");
exports.commands = require("./commands/multi_select_commands");
var commands = require("./commands/multi_select_commands");
exports.commands = commands.defaultCommands.concat(commands.multiSelectCommands);
// Todo: session.find or editor.findVolatile that returns range
var Search = require("./search").Search;
@ -397,7 +398,7 @@ var Editor = require("./editor").Editor;
this.inMultiSelectMode = true;
this.setStyle("multiselect");
this.keyBinding.addKeyboardHandler(exports.commands.keyboardHandler);
this.keyBinding.addKeyboardHandler(commands.keyboardHandler);
this.commands.on("exec", this.$onMultiSelectExec);
this.renderer.updateCursor();
@ -410,7 +411,7 @@ var Editor = require("./editor").Editor;
this.inMultiSelectMode = false;
this.unsetStyle("multiselect");
this.keyBinding.removeKeyboardHandler(exports.commands.keyboardHandler);
this.keyBinding.removeKeyboardHandler(commands.keyboardHandler);
this.commands.removeEventListener("exec", this.$onMultiSelectExec);
this.renderer.updateCursor();
@ -420,6 +421,8 @@ var Editor = require("./editor").Editor;
this.$onMultiSelectExec = function(e) {
var command = e.command;
var editor = e.editor;
if (!editor.multiSelect)
return;
if (!command.multiSelectAction) {
command.exec(editor, e.args || {});
editor.multiSelect.addRange(editor.multiSelect.toOrientedRange());
@ -724,7 +727,7 @@ function MultiSelect(editor) {
editor.on("changeSession", exports.onSessionChange.bind(editor));
editor.on("mousedown", onMouseDown);
editor.commands.addCommands(exports.commands.defaultCommands);
editor.commands.addCommands(commands.defaultCommands);
addAltCursorListeners(editor);
}

View file

@ -196,10 +196,9 @@ var RangeList = function() {
var lineDif = endRow - startRow;
var colDiff = -start.column + end.column;
var ranges = this.ranges;
for (var i=0, n = ranges.length; i < n; i++) {
for (var i = 0, n = ranges.length; i < n; i++) {
var r = ranges[i];
if (r.end.row < startRow)
continue;

View file

@ -54,35 +54,25 @@ var Range = require("./range").Range;
/**
* new Search()
*
* Creates a new `Search` object. The search options contain the following defaults:
* Creates a new `Search` object. The following search options are avaliable:
*
* * `needle`: `""`
* * `backwards`: `false`
* * `wrap`: `false`
* * `caseSensitive`: `false`
* * `wholeWord`: `false`
* * `scope`: `ALL`
* * `regExp`: `false`
* * needle: string or regular expression
* * backwards: false
* * wrap: false
* * caseSensitive: false
* * wholeWord: false
* * range: Range or null for whole document
* * regExp: false
* * start: Range or position
* * skipCurrent: false
*
**/
var Search = function() {
this.$options = {
needle: "",
backwards: false,
wrap: false,
caseSensitive: false,
wholeWord: false,
scope: Search.ALL,
regExp: false
};
this.$options = {};
};
Search.ALL = 1;
Search.SELECTION = 2;
(function() {
/**
* Search.set(options) -> Search
* - options (Object): An object containing all the new search properties
@ -105,6 +95,9 @@ Search.SELECTION = 2;
return lang.copyObject(this.$options);
};
this.setOptions = function(options) {
this.$options = options;
};
/**
* Search.find(session) -> Range
* - session (EditSession): The session to search with
@ -113,17 +106,18 @@ Search.SELECTION = 2;
*
**/
this.find = function(session) {
if (!this.$options.needle)
return null;
var iterator = this.$matchIterator(session);
var iterator = this.$matchIterator(session, this.$options);
if (!iterator)
return false;
var firstRange = null;
iterator.forEach(function(range) {
firstRange = range;
iterator.forEach(function(range, row, offset) {
if (!range.start) {
var column = range.offset + (offset || 0);
firstRange = new Range(row, column, row, column+range.length);
} else
firstRange = range;
return true;
});
@ -141,23 +135,53 @@ Search.SELECTION = 2;
var options = this.$options;
if (!options.needle)
return [];
this.$assembleRegExp(options);
var iterator = this.$matchIterator(session);
if (!iterator)
return false;
var ignoreCursor = !options.start && options.wrap && options.scope == Search.ALL;
if (ignoreCursor)
options.start = {row: 0, column: 0};
if (options.range) {
var range = options.range;
var lines = session.getLines(range.start.row, range.end.row);
} else
var lines = session.doc.getAllLines();
var ranges = [];
iterator.forEach(function(range) {
ranges.push(range);
});
var re = options.re;
if (options.$isMultiLine) {
var len = re.length;
var maxRow = lines.length - len;
for (var row = re.offset || 0; row < maxRow; row++) {
for (var j = 0; j < re.length; j++)
if (lines[row + j].search(re[j]) == -1)
break;
if (ignoreCursor)
options.start = null;
var startIndex = lines[row + j].match(re[0])[0].length;
var endIndex = line.match(re[len - 1])[0].length;
ranges.push(new Range(
row, startLine.length - startIndex,
row + len - 1, endIndex
));
}
} else {
for (var i = 0; i < lines.length; i++) {
var matches = lang.getMatchOffsets(lines[i], re);
for (var j = 0; j < matches.length; j++) {
var match = matches[j];
ranges.push(new Range(i, match.offset, i, match.offset + match.length));
};
}
}
if (options.range) {
var startColumn = range.start.column;
var endColumn = range.start.column;
var i = 0, j = ranges.length - 1;
while (i < j && ranges[i].start.column < startColumn && ranges[i].start.row == range.start.row)
i++;
while (i < j && ranges[j].end.column > endColumn && ranges[j].end.row == range.end.row)
j--;
return ranges.slice(i, j + 1);
}
return ranges;
};
@ -173,252 +197,195 @@ Search.SELECTION = 2;
*
**/
this.replace = function(input, replacement) {
if (!this.$options.regExp)
return input == this.$options.needle ? replacement : null;
var re = this.$assembleRegExp();
var options = this.$options;
var re = this.$assembleRegExp(options);
if (options.$isMultiLine)
return replacement;
if (!re)
return;
var match = re.exec(input);
if (match && match[0].length == input.length) {
return input.replace(re, replacement);
}
else {
if (!match || match[0].length != input.length)
return null;
replacement = input.replace(re, replacement)
if (options.preserveCase) {
replacement = replacement.split("");
for (var i = Math.min(input.length, input.length); i--; ) {
var ch = input[i];
if (ch && ch.toLowerCase() != ch)
replacement[i] = replacement[i].toUpperCase();
else
replacement[i] = replacement[i].toLowerCase();
}
replacement = replacement.join("");
}
return replacement;
};
/** internal, hide
* Search.$matchIterator(session) -> String | Boolean
* - session (EditSession): The session to search with
*
*
*
**/
this.$matchIterator = function(session) {
var re = this.$assembleRegExp();
this.$matchIterator = function(session, options) {
var re = this.$assembleRegExp(options);
if (!re)
return false;
var self = this, callback, backwards = this.$options.backwards;
var self = this, callback, backwards = options.backwards;
if (this.$options.$isMultiLine) {
var matchIterator = function(line, startIndex, row) {
var startLine = line;
if (startIndex)
line = line.substring(startIndex);
var len = re.length;
var part = re[0];
if (line.slice(-part.length) != part)
if (options.$isMultiLine) {
var len = re.length;
var matchIterator = function(line, row, offset) {
var startIndex = line.search(re[0]);
if (startIndex == -1)
return;
for (var i = 1; i < len - 1; i++)
if (re[i] != session.getLine(row + i))
for (var i = 1; i < len; i++) {
line = session.getLine(row + i);
if (line.search(re[i]) == -1)
return;
}
part = re[len - 1];
if (session.getLine(row + len - 1).slice(0, part.length) != part)
return;
var endIndex = line.match(re[len - 1])[0].length;
var range = new Range(row, startIndex, row + len - 1, endIndex);
if (re.offset == 1) {
range.start.row--;
range.start.column = Number.MAX_VALUE;
} else if (offset)
range.start.column += offset;
var range = new Range(
row, startLine.length - re[0].length,
row + len - 1, re[len - 1].length
);
if (callback(range))
return true;
}
} else if (backwards) {
var matchIterator = function(line, startIndex, row) {
if (startIndex)
line = line.substring(startIndex);
var matches = [];
line.replace(re, function(str) {
var offset = arguments[arguments.length-2];
matches.push({
str: str,
offset: startIndex + offset
});
return str;
});
for (var i=matches.length-1; i>= 0; i--) {
var match = matches[i];
var range = self.$rangeFromMatch(row, match.offset, match.str.length);
if (callback(range))
var matchIterator = function(line, row, startIndex) {
var matches = lang.getMatchOffsets(line, re);
for (var i = matches.length-1; i >= 0; i--)
if (callback(matches[i], row, startIndex))
return true;
}
}
} else {
var matchIterator = function(line, startIndex, row) {
if (startIndex)
line = line.substring(startIndex);
var matches = [];
line.replace(re, function(str) {
var offset = arguments[arguments.length-2];
matches.push({
str: str,
offset: startIndex + offset
});
return str;
});
for (var i=0; i<matches.length; i++) {
var match = matches[i];
var range = self.$rangeFromMatch(row, match.offset, match.str.length);
if (callback(range))
var matchIterator = function(line, row, startIndex) {
var matches = lang.getMatchOffsets(line, re);
for (var i = 0; i < matches.length; i++)
if (callback(matches[i], row, startIndex))
return true;
}
}
}
return {forEach: function(_callback) {
callback = _callback;
self.$lineIterator(session).forEach(matchIterator);
}};
};
this.$rangeFromMatch = function(row, column, length) {
return new Range(row, column, row, column+length);
};
this.$assembleRegExp = function() {
if (typeof this.$options.needle != 'string')
return this.$options.needle;
var needle = this.$options.needle;
if (!this.$options.regExp) {
if (/[\n\r]/.test(needle)){
this.$options.$isMultiLine = true;
return needle.split(/\r\n|\r|\n/)
return {
forEach: function(_callback) {
callback = _callback;
self.$lineIterator(session, options).forEach(matchIterator);
}
};
};
this.$assembleRegExp = function(options) {
if (options.needle instanceof RegExp)
return options.re = options.needle;
var needle = options.needle;
if (!options.needle)
return options.re = false;
if (!options.regExp)
needle = lang.escapeRegExp(needle);
}
this.$options.$isMultiLine = false;
if (this.$options.wholeWord) {
if (options.wholeWord)
needle = "\\b" + needle + "\\b";
}
var modifier = "g";
if (!this.$options.caseSensitive) {
modifier += "i";
}
var modifier = options.caseSensitive ? "g" : "gi";
options.$isMultiLine = /[\n\r]/.test(needle);
if (options.$isMultiLine)
return options.re = this.$assembleMultilineRegExp(needle, modifier);
try {
var re = new RegExp(needle, modifier);
} catch(e) {
var re = false;
}
catch(e) {
return options.re = re;
};
this.$assembleMultilineRegExp = function(needle, modifier) {
var parts = needle.replace(/\r\n|\r|\n/g, "$\n^").split("\n");
var re = [];
for (var i = 0; i < parts.length; i++) try {
re.push(new RegExp(parts[i], modifier));
} catch(e) {
return false;
}
if (parts[0] == "") {
re.shift();
re.offset = 1;
} else {
re.offset = 0;
}
return re;
};
this.$lineIterator = function(session) {
var searchSelection = this.$options.scope == Search.SELECTION;
var backwards = this.$options.backwards;
this.$lineIterator = function(session, options) {
var range = options.range;
var backwards = options.backwards == true;
var skipCurrent = options.skipCurrent != false;
var range = this.$options.range || session.getSelection().getRange();
var start = this.$options.start || range[searchSelection != backwards ? "start" : "end"];
var range = options.range;
var start = options.start;
if (!start)
start = range ? range[backwards ? "end" : "start"] : session.selection.getRange();
if (start.start)
start = start[skipCurrent != backwards ? "end" : "start"];
var firstRow = searchSelection ? range.start.row : 0;
var firstColumn = searchSelection ? range.start.column : 0;
var lastRow = searchSelection ? range.end.row : session.getLength() - 1;
var wrap = this.$options.wrap;
var inWrap = false;
function getLine(row) {
var line = session.getLine(row);
if (searchSelection && row == range.end.row) {
line = line.substring(0, range.end.column);
}
if (inWrap && row == start.row) {
line = line.substring(0, start.column);
}
return line;
}
var firstRow = range ? range.start.row : 0;
var firstColumn = range ? range.start.column : 0;
var lastRow = range ? range.end.row : session.getLength() - 1;
if (!backwards) {
var forEach = function(callback) {
var row = start.row;
var line = getLine(row);
var startIndex = start.column;
var line = session.getLine(row).substr(start.column);
if (callback(line, row, start.column))
return;
var stop = false;
inWrap = false;
while (!callback(line, startIndex, row)) {
if (stop)
for (row = row+1; row <= lastRow; row++)
if (callback(session.getLine(row), row))
return;
row++;
startIndex = 0;
if (options.wrap == false)
return;
if (row > lastRow) {
if (wrap) {
row = firstRow;
startIndex = firstColumn;
inWrap = true;
} else {
return;
}
}
if (row == start.row)
stop = true;
line = getLine(row);
}
for (row = firstRow, lastRow = start.row; row <= lastRow; row++)
if (callback(session.getLine(row), row))
return;
}
} else {
var forEach = function(callback) {
var row = start.row;
var line = session.getLine(row).substring(0, start.column);
var startIndex = 0;
var stop = false;
var inWrap = false;
if (callback(line, row))
return;
while (!callback(line, startIndex, row)) {
if (stop)
for (row--; row >= firstRow; row--)
if (callback(session.getLine(row), row))
return;
row--;
startIndex = 0;
if (options.wrap == false)
return;
if (row < firstRow) {
if (wrap) {
row = lastRow;
inWrap = true;
} else {
return;
}
}
if (row == start.row)
stop = true;
line = session.getLine(row);
if (searchSelection) {
if (row == firstRow)
startIndex = firstColumn;
else if (row == lastRow)
line = line.substring(0, range.end.column);
}
if (inWrap && row == start.row)
startIndex = start.column;
}
for (row = lastRow, firstRow = start.row; row >= firstRow; row--)
if (callback(session.getLine(row), row))
return;
}
}

View file

@ -0,0 +1,87 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Harutyun Amirjanyan <harutyun@c9.io>
*
* 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
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var lang = require("./lib/lang");
var oop = require("./lib/oop");
var Range = require("./range").Range;
var SearchHighlight = function(regExp, clazz, type) {
this.setRegexp(regExp);
this.clazz = clazz;
this.type = type || "text";
};
(function() {
this.setRegexp = function(regExp) {
if (this.regExp+"" == regExp+"")
return;
this.regExp = regExp;
this.cache = [];
};
this.update = function(html, markerLayer, session, config) {
if (!this.regExp)
return;
var start = config.firstRow, end = config.lastRow;
for (var i = start; i <= end; i++) {
var ranges = this.cache[i];
if (ranges == null) {
ranges = lang.getMatchOffsets(session.getLine(i), this.regExp);
ranges = ranges.map(function(match) {
return new Range(i, match.offset, i, match.offset + match.length);
});
this.cache[i] = ranges.length ? ranges : "";
}
for (var j = ranges.length; j --; ) {
markerLayer.drawSingleLineMarker(
html, ranges[j].toScreenRange(session), this.clazz, config,
null, this.type
);
}
}
};
}).call(SearchHighlight.prototype);
exports.SearchHighlight = SearchHighlight;
});

View file

@ -52,7 +52,6 @@ module.exports = {
var search = new Search();
search.set({
needle: "juhu",
scope: Search.ALL
});
},
@ -90,7 +89,7 @@ module.exports = {
assert.position(range.end, 1, 12);
},
"test: wrap search is off by default" : function() {
"test: wrap search is on by default" : function() {
var session = new EditSession(["abc", "juhu kinners 123", "456"]);
session.getSelection().moveCursorTo(2, 1);
@ -98,7 +97,7 @@ module.exports = {
needle: "kinners"
});
assert.equal(search.find(session), null);
assert.notEqual(search.find(session), null);
},
"test: wrap search should wrap at file end" : function() {
@ -115,6 +114,20 @@ module.exports = {
assert.position(range.end, 1, 12);
},
"test: wrap search should find needle even if it starts inside it" : function() {
var session = new EditSession(["abc", "juhu kinners 123", "456"]);
session.getSelection().moveCursorTo(6, 1);
var search = new Search().set({
needle: "kinners",
wrap: true
});
var range = search.find(session);
assert.position(range.start, 1, 5);
assert.position(range.end, 1, 12);
},
"test: wrap search with no match should return 'null'": function() {
var session = new EditSession(["abc", "juhu kinners 123", "456"]);
session.getSelection().moveCursorTo(2, 1);
@ -183,13 +196,19 @@ module.exports = {
var search = new Search().set({
needle: "juhu",
wrap: true,
scope: Search.SELECTION
range: session.getSelection().getRange()
});
var range = search.find(session);
assert.position(range.start, 1, 0);
assert.position(range.end, 1, 4);
search = new Search().set({
needle: "juhu",
wrap: true,
range: session.getSelection().getRange()
});
session.getSelection().setSelectionAnchor(0, 2);
session.getSelection().selectTo(3, 2);
@ -201,24 +220,32 @@ module.exports = {
"test: find backwards in selection": function() {
var session = new EditSession(["juhu", "juhu", "juhu", "juhu"]);
session.getSelection().setSelectionAnchor(0, 2);
session.getSelection().selectTo(3, 2);
var search = new Search().set({
needle: "juhu",
wrap: true,
backwards: true,
scope: Search.SELECTION
range: session.getSelection().getRange()
});
session.getSelection().setSelectionAnchor(0, 2);
session.getSelection().selectTo(3, 2);
var range = search.find(session);
assert.position(range.start, 2, 0);
assert.position(range.end, 2, 4);
search = new Search().set({
needle: "juhu",
wrap: true,
range: session.getSelection().getRange()
});
session.getSelection().setSelectionAnchor(0, 2);
session.getSelection().selectTo(1, 2);
assert.equal(search.find(session), null);
var range = search.find(session);
assert.position(range.start, 1, 0);
assert.position(range.end, 1, 4);
},
"test: edge case - match directly before the cursor" : function() {
@ -295,15 +322,15 @@ module.exports = {
"test: find all matches in selection" : function() {
var session = new EditSession(["juhu", "juhu", "juhu", "juhu"]);
session.getSelection().setSelectionAnchor(0, 2);
session.getSelection().selectTo(3, 2);
var search = new Search().set({
needle: "uh",
wrap: true,
scope: Search.SELECTION
range: session.getSelection().getRange()
});
session.getSelection().setSelectionAnchor(0, 2);
session.getSelection().selectTo(3, 2);
var ranges = search.findAll(session);
assert.equal(ranges.length, 2);
@ -322,6 +349,11 @@ module.exports = {
assert.equal(search.replace("", "kinners"), null);
assert.equal(search.replace(" juhu", "kinners"), null);
// case sensitivity
assert.equal(search.replace("Juhu", "kinners"), "kinners");
search.set({caseSensitive: true});
assert.equal(search.replace("Juhu", "kinners"), null);
// regexp replacement
},
@ -356,7 +388,6 @@ module.exports = {
needle: "[ ]+$",
regExp: true,
wrap: true,
scope: Search.ALL
});
session.getSelection().moveCursorTo(1, 2);
@ -404,12 +435,12 @@ module.exports = {
var ranges = search.findAll(session);
assert.equal(ranges.length, 3);
assert.position(ranges[0].start, 0, 23);
assert.position(ranges[0].end, 0, 26);
assert.position(ranges[2].start, 0, 23);
assert.position(ranges[2].end, 0, 26);
assert.position(ranges[1].start, 0, 8);
assert.position(ranges[1].end, 0, 11);
assert.position(ranges[2].start, 0, 0);
assert.position(ranges[2].end, 0, 3);
assert.position(ranges[0].start, 0, 0);
assert.position(ranges[0].end, 0, 3);
},
};

View file

@ -55,7 +55,7 @@ var Range = require("./range").Range;
/**
* new Selection(session)
* - session (EditSession): The session to use
*
*
* Creates a new `Selection` object.
*
**/
@ -88,7 +88,7 @@ var Selection = function(session) {
/**
* Selection.isEmpty() -> Boolean
*
*
* Returns `true` if the selection is empty.
**/
this.isEmpty = function() {
@ -100,7 +100,7 @@ var Selection = function(session) {
/**
* Selection.isMultiLine() -> Boolean
*
*
* Returns `true` if the selection is a multi-line.
**/
this.isMultiLine = function() {
@ -113,7 +113,7 @@ var Selection = function(session) {
/**
* Selection.getCursor() -> Number
*
*
* Gets the current position of the cursor.
**/
this.getCursor = function() {
@ -121,7 +121,7 @@ var Selection = function(session) {
};
/**
* Selection.setSelectionAnchor(row, column)
* Selection.setSelectionAnchor(row, column)
* - row (Number): The new row
* - column (Number): The new column
*
@ -138,7 +138,7 @@ var Selection = function(session) {
/** related to: Anchor.getPosition
* Selection.getSelectionAnchor() -> Object
*
*
* Returns an object containing the `row` and `column` of the calling selection anchor.
*
**/
@ -149,9 +149,9 @@ var Selection = function(session) {
return this.anchor.getPosition();
};
/**
/**
* Selection.getSelectionLead() -> Object
*
*
* Returns an object containing the `row` and `column` of the calling selection lead.
**/
this.getSelectionLead = function() {
@ -159,9 +159,9 @@ var Selection = function(session) {
};
/**
* Selection.shiftSelection(columns)
* Selection.shiftSelection(columns)
* - columns (Number): The number of columns to shift by
*
*
* Shifts the selection up (or down, if [[Selection.isBackwards `isBackwards()`]] is true) the given number of columns.
*
**/
@ -188,7 +188,7 @@ var Selection = function(session) {
/**
* Selection.isBackwards() -> Boolean
*
*
* Returns `true` if the selection is going backwards in the document.
**/
this.isBackwards = function() {
@ -199,7 +199,7 @@ var Selection = function(session) {
/**
* Selection.getRange() -> Range
*
*
* [Returns the [[Range `Range`]] for the selected text.]{: #Selection.getRange}
**/
this.getRange = function() {
@ -218,8 +218,8 @@ var Selection = function(session) {
};
/**
* Selection.clearSelection()
*
* Selection.clearSelection()
*
* [Empties the selection (by de-selecting it). This function also emits the `'changeSelection'` event.]{: #Selection.clearSelection}
**/
this.clearSelection = function() {
@ -230,24 +230,25 @@ var Selection = function(session) {
};
/**
* Selection.selectAll()
*
* Selection.selectAll()
*
* Selects all the text in the document.
**/
this.selectAll = function() {
var lastRow = this.doc.getLength() - 1;
this.setSelectionAnchor(lastRow, this.doc.getLine(lastRow).length);
this.moveCursorTo(0, 0);
this.setSelectionAnchor(0, 0);
this.moveCursorTo(lastRow, this.doc.getLine(lastRow).length);
};
/**
* Selection.setSelectionRange(range, reverse)
* Selection.setSelectionRange(range, reverse)
* - range (Range): The range of text to select
* - reverse (Boolean): Indicates if the range should go backwards (`true`) or not
*
* Sets the selection to the provided range.
*
**/
this.setRange =
this.setSelectionRange = function(range, reverse) {
if (reverse) {
this.setSelectionAnchor(range.end.row, range.end.column);
@ -268,7 +269,7 @@ var Selection = function(session) {
};
/**
* Selection.selectTo(row, column)
* Selection.selectTo(row, column)
* - row (Number): The row to select to
* - column (Number): The column to select to
*
@ -282,9 +283,9 @@ var Selection = function(session) {
};
/**
* Selection.selectToPosition(pos)
* Selection.selectToPosition(pos)
* - pos (Object): An object containing the row and column
*
*
* Moves the selection cursor to the row and column indicated by `pos`.
*
**/
@ -295,8 +296,8 @@ var Selection = function(session) {
};
/**
* Selection.selectUp()
*
* Selection.selectUp()
*
* Moves the selection up one row.
**/
this.selectUp = function() {
@ -304,8 +305,8 @@ var Selection = function(session) {
};
/**
* Selection.selectDown()
*
* Selection.selectDown()
*
* Moves the selection down one row.
**/
this.selectDown = function() {
@ -313,8 +314,8 @@ var Selection = function(session) {
};
/**
* Selection.selectRight()
*
* Selection.selectRight()
*
* Moves the selection right one column.
**/
this.selectRight = function() {
@ -322,8 +323,8 @@ var Selection = function(session) {
};
/**
* Selection.selectLeft()
*
* Selection.selectLeft()
*
* Moves the selection left one column.
**/
this.selectLeft = function() {
@ -331,8 +332,8 @@ var Selection = function(session) {
};
/**
* Selection.selectLineStart()
*
* Selection.selectLineStart()
*
* Moves the selection to the beginning of the current line.
**/
this.selectLineStart = function() {
@ -340,8 +341,8 @@ var Selection = function(session) {
};
/**
* Selection.selectLineEnd()
*
* Selection.selectLineEnd()
*
* Moves the selection to the end of the current line.
**/
this.selectLineEnd = function() {
@ -349,8 +350,8 @@ var Selection = function(session) {
};
/**
* Selection.selectFileEnd()
*
* Selection.selectFileEnd()
*
* Moves the selection to the end of the file.
**/
this.selectFileEnd = function() {
@ -358,8 +359,8 @@ var Selection = function(session) {
};
/**
* Selection.selectFileStart()
*
* Selection.selectFileStart()
*
* Moves the selection to the start of the file.
**/
this.selectFileStart = function() {
@ -367,8 +368,8 @@ var Selection = function(session) {
};
/**
* Selection.selectWordRight()
*
* Selection.selectWordRight()
*
* Moves the selection to the first word on the right.
**/
this.selectWordRight = function() {
@ -376,8 +377,8 @@ var Selection = function(session) {
};
/**
* Selection.selectWordLeft()
*
* Selection.selectWordLeft()
*
* Moves the selection to the first word on the left.
**/
this.selectWordLeft = function() {
@ -385,8 +386,8 @@ var Selection = function(session) {
};
/** related to: EditSession.getWordRange
* Selection.selectWord()
*
* Selection.selectWord()
*
* Moves the selection to highlight the entire word.
**/
this.getWordRange = function(row, column) {
@ -403,8 +404,8 @@ var Selection = function(session) {
};
/** related to: EditSession.getAWordRange
* Selection.selectAWord()
*
* Selection.selectAWord()
*
* Selects a word, including its right whitespace.
**/
this.selectAWord = function() {
@ -430,9 +431,9 @@ var Selection = function(session) {
return new Range(rowStart, 0, rowEnd + 1, 0);
};
/**
* Selection.selectLine()
*
/**
* Selection.selectLine()
*
* Selects the entire line.
**/
this.selectLine = function() {
@ -440,8 +441,8 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorUp()
*
* Selection.moveCursorUp()
*
* Moves the cursor up one row.
**/
this.moveCursorUp = function() {
@ -449,8 +450,8 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorDown()
*
* Selection.moveCursorDown()
*
* Moves the cursor down one row.
**/
this.moveCursorDown = function() {
@ -458,8 +459,8 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorLeft()
*
* Selection.moveCursorLeft()
*
* Moves the cursor left one column.
**/
this.moveCursorLeft = function() {
@ -484,8 +485,8 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorRight()
*
* Selection.moveCursorRight()
*
* Moves the cursor right one column.
**/
this.moveCursorRight = function() {
@ -510,8 +511,8 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorLineStart()
*
* Selection.moveCursorLineStart()
*
* Moves the cursor to the start of the line.
**/
this.moveCursorLineStart = function() {
@ -543,8 +544,8 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorLineEnd()
*
* Selection.moveCursorLineEnd()
*
* Moves the cursor to the end of the line.
**/
this.moveCursorLineEnd = function() {
@ -558,8 +559,8 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorFileEnd()
*
* Selection.moveCursorFileEnd()
*
* Moves the cursor to the end of the file.
**/
this.moveCursorFileEnd = function() {
@ -569,8 +570,8 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorFileStart()
*
* Selection.moveCursorFileStart()
*
* Moves the cursor to the start of the file.
**/
this.moveCursorFileStart = function() {
@ -578,8 +579,8 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorLongWordRight()
*
* Selection.moveCursorLongWordRight()
*
* Moves the cursor to the word on the right.
**/
this.moveCursorLongWordRight = function() {
@ -598,14 +599,14 @@ var Selection = function(session) {
this.moveCursorTo(fold.end.row, fold.end.column);
return;
}
// first skip space
if (match = this.session.nonTokenRe.exec(rightOfCursor)) {
column += this.session.nonTokenRe.lastIndex;
this.session.nonTokenRe.lastIndex = 0;
rightOfCursor = line.substring(column);
}
// if at line end proceed with next line
if (column >= line.length) {
this.moveCursorTo(row, line.length);
@ -614,7 +615,7 @@ var Selection = function(session) {
this.moveCursorWordRight();
return;
}
// advance to the end of the next token
if (match = this.session.tokenRe.exec(rightOfCursor)) {
column += this.session.tokenRe.lastIndex;
@ -625,8 +626,8 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorLongWordLeft()
*
* Selection.moveCursorLongWordLeft()
*
* Moves the cursor to the word on the left.
**/
this.moveCursorLongWordLeft = function() {
@ -644,19 +645,19 @@ var Selection = function(session) {
if (str == null) {
str = this.doc.getLine(row).substring(0, column)
}
var leftOfCursor = lang.stringReverse(str);
var match;
this.session.nonTokenRe.lastIndex = 0;
this.session.tokenRe.lastIndex = 0;
// skip whitespace
if (match = this.session.nonTokenRe.exec(leftOfCursor)) {
column -= this.session.nonTokenRe.lastIndex;
leftOfCursor = leftOfCursor.slice(this.session.nonTokenRe.lastIndex);
this.session.nonTokenRe.lastIndex = 0;
}
// if at begin of the line proceed in line above
if (column <= 0) {
this.moveCursorTo(row, 0);
@ -721,8 +722,17 @@ var Selection = function(session) {
if (fold)
return this.moveCursorTo(fold.end.row, fold.end.column);
if (column == line.length)
return this.moveCursorRight();
if (column == line.length) {
var l = this.doc.getLength();
do {
row++;
rightOfCursor = this.doc.getLine(row)
} while (row < l && /^\s*$/.test(rightOfCursor))
if (!/^\s+/.test(rightOfCursor))
rightOfCursor = ""
column = 0;
}
var index = this.$shortWordEndIndex(rightOfCursor);
@ -737,11 +747,19 @@ var Selection = function(session) {
if (fold = this.session.getFoldAt(row, column, -1))
return this.moveCursorTo(fold.start.row, fold.start.column);
if (column == 0)
return this.moveCursorLeft();
var line = this.session.getLine(row).substring(0, column);
if (column == 0) {
do {
row--;
line = this.doc.getLine(row);
} while (row > 0 && /^\s*$/.test(line))
column = line.length;
if (!/\s+$/.test(line))
line = ""
}
var str = this.session.getLine(row).substring(0, column);
var leftOfCursor = lang.stringReverse(str);
var leftOfCursor = lang.stringReverse(line);
var index = this.$shortWordEndIndex(leftOfCursor);
return this.moveCursorTo(row, column - index);
@ -762,7 +780,7 @@ var Selection = function(session) {
};
/** related to: EditSession.documentToScreenPosition
* Selection.moveCursorBy(rows, chars)
* Selection.moveCursorBy(rows, chars)
* - rows (Number): The number of rows to move by
* - chars (Number): The number of characters to move by
*
@ -788,9 +806,9 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorToPosition(position)
* Selection.moveCursorToPosition(position)
* - position (Object): The position to move to
*
*
* Moves the selection to the position indicated by its `row` and `column`.
**/
this.moveCursorToPosition = function(position) {
@ -798,7 +816,7 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorTo(row, column, keepDesiredColumn)
* Selection.moveCursorTo(row, column, keepDesiredColumn)
* - row (Number): The row to move to
* - column (Number): The column to move to
* - keepDesiredColumn (Boolean): [If `true`, the cursor move does not respect the previous column]{: #preventUpdateBool}
@ -822,7 +840,7 @@ var Selection = function(session) {
};
/**
* Selection.moveCursorToScreen(row, column, keepDesiredColumn)
* Selection.moveCursorToScreen(row, column, keepDesiredColumn)
* - row (Number): The row to move to
* - column (Number): The column to move to
* - keepDesiredColumn (Boolean): {:preventUpdateBool}

View file

@ -11,6 +11,7 @@ var log = document.getElementById("log")
var testNames = [
"ace/anchor_test",
"ace/background_tokenizer_test",
"ace/commands/command_manager_test",
"ace/document_test",
"ace/edit_session_test",
@ -65,7 +66,11 @@ if (location.search)
testNames = location.search.substr(1).split(",")
require(testNames, function() {
var tests = testNames.map(require);
var tests = testNames.map(function(x) {
var module = require(x);
module.href = x;
return module;
});
async.list(tests)
.expand(function(test) {
@ -73,6 +78,12 @@ require(testNames, function() {
}, AsyncTest.TestGenerator)
.run()
.each(function(test, next) {
if (test.index == 1 && test.context.href) {
var href = test.context.href;
var node = document.createElement("div");
node.innerHTML = "<a href='?" + href + "'>" + href.replace(/^ace\//, "") + "</a>";
log.appendChild(node);
}
var node = document.createElement("div");
node.className = test.passed ? "passed" : "failed";

View file

@ -163,7 +163,7 @@ MockRenderer.prototype.updateBackMarkers = function() {
MockRenderer.prototype.updateFrontMarkers = function() {
};
MockRenderer.prototype.setBreakpoints = function() {
MockRenderer.prototype.updateBreakpoints = function() {
};
MockRenderer.prototype.onResize = function() {

View file

@ -57,6 +57,10 @@
background: #FFFBD1;
}
.ace-clouds .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-clouds .ace_marker-layer .ace_selected_word {
border: 1px solid #BDD5FC;
}

View file

@ -57,6 +57,10 @@
background: rgba(215, 215, 215, 0.031);
}
.ace-clouds-midnight .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-clouds-midnight .ace_marker-layer .ace_selected_word {
border: 1px solid #000000;
}

View file

@ -57,6 +57,10 @@
background: rgba(0, 0, 0, 0.35);
}
.ace-cobalt .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-cobalt .ace_marker-layer .ace_selected_word {
border: 1px solid rgba(179, 101, 57, 0.75);
}

View file

@ -57,6 +57,10 @@
background: rgba(36, 99, 180, 0.12);
}
.ace-dawn .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-dawn .ace_marker-layer .ace_selected_word {
border: 1px solid rgba(39, 95, 255, 0.30);
}

View file

@ -57,6 +57,10 @@
background: #353637;
}
.ace-idle-fingers .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-idle-fingers .ace_marker-layer .ace_selected_word {
border: 1px solid rgba(90, 100, 126, 0.88);
}

View file

@ -57,6 +57,10 @@
background: #38403D;
}
.ace-kr-theme .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-kr-theme .ace_marker-layer .ace_selected_word {
border: 1px solid rgba(170, 0, 255, 0.45);
}

View file

@ -57,6 +57,10 @@
background: #333435;
}
.ace-merbivore .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-merbivore .ace_marker-layer .ace_selected_word {
border: 1px solid #454545;
}

View file

@ -57,6 +57,10 @@
background: #333435;
}
.ace-merbivore-soft .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-merbivore-soft .ace_marker-layer .ace_selected_word {
border: 1px solid #494949;
}

View file

@ -57,6 +57,10 @@
background: rgba(12, 13, 12, 0.25);
}
.ace-mono-industrial .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-mono-industrial .ace_marker-layer .ace_selected_word {
border: 1px solid rgba(145, 153, 148, 0.40);
}

View file

@ -53,11 +53,11 @@
border: 1px solid #49483E;
}
.ace-monokai .ace_marker-layer .ace_active_line{
.ace-monokai .ace_marker-layer .ace_active_line {
background: #49483E;
}
.ace-monokai .ace_gutter_active_line{
background: #191916;
.ace-monokai .ace_gutter_active_line {
background-color: #191916;
}
.ace-monokai .ace_marker-layer .ace_selected_word {

View file

@ -57,6 +57,10 @@
background: rgba(255, 255, 255, 0.031);
}
.ace-pastel-on-dark .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-pastel-on-dark .ace_marker-layer .ace_selected_word {
border: 1px solid rgba(221, 240, 255, 0.20);
}

View file

@ -56,8 +56,9 @@
.ace-solarized-dark .ace_marker-layer .ace_active_line {
background: #073642;
}
.ace-solarized-dark .ace_gutter_active_line{
background: #0d3440;
.ace-solarized-dark .ace_gutter_active_line {
background-color: #0d3440;
}
.ace-solarized-dark .ace_marker-layer .ace_selected_word {

View file

@ -57,6 +57,10 @@
background: #EEE8D5;
}
.ace-solarized-light .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-solarized-light .ace_marker-layer .ace_selected_word {
border: 1px solid #073642;
}

View file

@ -57,6 +57,10 @@
background: #EFEFEF;
}
.ace-tomorrow .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-tomorrow .ace_marker-layer .ace_selected_word {
border: 1px solid #D6D6D6;
}

View file

@ -57,6 +57,10 @@
background: #282A2E;
}
.ace-tomorrow-night .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-tomorrow-night .ace_marker-layer .ace_selected_word {
border: 1px solid #373B41;
}

View file

@ -53,11 +53,12 @@
border: 1px solid #404F7D;
}
.ace-tomorrow-night-blue .ace_marker-layer .ace_active_line{
.ace-tomorrow-night-blue .ace_marker-layer .ace_active_line {
background: #00346E;
}
.ace-tomorrow-night-blue .ace_gutter_active_line{
background: #022040;
.ace-tomorrow-night-blue .ace_gutter_active_line {
background-color: #022040;
}
.ace-tomorrow-night-blue .ace_marker-layer .ace_selected_word {

View file

@ -57,6 +57,10 @@
background: #2A2A2A;
}
.ace-tomorrow-night-bright .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-tomorrow-night-bright .ace_marker-layer .ace_selected_word {
border: 1px solid #424242;
}

View file

@ -57,6 +57,10 @@
background: #393939;
}
.ace-tomorrow-night-eighties .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-tomorrow-night-eighties .ace_marker-layer .ace_selected_word {
border: 1px solid #515151;
}

View file

@ -57,6 +57,10 @@
background: rgba(255, 255, 255, 0.031);
}
.ace-twilight .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-twilight .ace_marker-layer .ace_selected_word {
border: 1px solid rgba(221, 240, 255, 0.20);
}

View file

@ -57,6 +57,10 @@
background: #333333;
}
.ace-vibrant-ink .ace_gutter_active_line {
background-color : #dcdcdc;
}
.ace-vibrant-ink .ace_marker-layer .ace_selected_word {
border: 1px solid #6699CC;
}

View file

@ -67,7 +67,7 @@ dom.importCssString(editorCss, "ace_editor");
/**
* new VirtualRenderer(container, theme)
* - container (DOMElement): The root element of the editor
* - container (DOMElement): The root element of the editor
* - theme (String): The starting theme
*
* Constructs a new `VirtualRenderer` within the `container` specified, applying the given `theme`.
@ -82,7 +82,7 @@ var VirtualRenderer = function(container, theme) {
// TODO: this breaks rendering in Cloud9 with multiple ace instances
// // Imports CSS once per DOM document ('ace_editor' serves as an identifier).
// dom.importCssString(editorCss, "ace_editor", container.ownerDocument);
// in IE <= 9 the native cursor always shines through
this.$keepTextAreaAtCursor = !useragent.isIE;
@ -102,7 +102,6 @@ var VirtualRenderer = function(container, theme) {
this.content.className = "ace_content";
this.scroller.appendChild(this.content);
this.setHighlightGutterLine(true);
this.$gutterLayer = new GutterLayer(this.$gutter);
this.$gutterLayer.on("changeGutterWidth", this.onResize.bind(this, true));
this.setFadeFoldWidgets(true);
@ -449,31 +448,38 @@ var VirtualRenderer = function(container, theme) {
dom.removeCssClass(this.$gutter, "ace_fade-fold-widgets");
};
this.$highlightGutterLine = false;
this.$highlightGutterLine = true;
this.setHighlightGutterLine = function(shouldHighlight) {
if (this.$highlightGutterLine == shouldHighlight)
return;
this.$highlightGutterLine = shouldHighlight;
if (!this.$gutterLineHighlight) {
this.$gutterLineHighlight = dom.createElement("div");
this.$gutterLineHighlight.className = "ace_gutter_active_line";
this.$gutter.appendChild(this.$gutterLineHighlight);
return;
}
this.$gutterLineHighlight.style.display = shouldHighlight ? "" : "none";
this.$updateGutterLineHighlight();
this.$loop.schedule(this.CHANGE_GUTTER);
};
this.getHighlightGutterLine = function() {
return this.$highlightGutterLine;
};
this.$updateGutterLineHighlight = function() {
this.$gutterLineHighlight.style.top = this.$cursorLayer.$pixelPos.top - this.layerConfig.offset + "px";
this.$gutterLineHighlight.style.height = this.layerConfig.lineHeight + "px";
this.$updateGutterLineHighlight = function(gutterReady) {
var i = this.session.selection.lead.row;
if (i == this.$gutterLineHighlight)
return;
if (!gutterReady) {
var ch = this.$gutterLayer.element.children
var oldEl = ch[this.$gutterLineHighlight - this.layerConfig.firstRow];
if (oldEl)
dom.removeCssClass(oldEl, "ace_gutter_active_line");
var newEl = ch[i - this.layerConfig.firstRow];
if (newEl)
dom.addCssClass(newEl, "ace_gutter_active_line");
}
this.$gutterLayer.removeGutterDecoration(this.$gutterLineHighlight, "ace_gutter_active_line");
this.$gutterLayer.addGutterDecoration(i, "ace_gutter_active_line");
this.$gutterLineHighlight = i;
};
this.$updatePrintMargin = function() {
@ -533,13 +539,23 @@ var VirtualRenderer = function(container, theme) {
var posLeft = this.$cursorLayer.$pixelPos.left;
posTop -= this.layerConfig.offset;
if (posTop < 0 || posTop > this.layerConfig.height)
if (posTop < 0 || posTop > this.layerConfig.height - this.lineHeight)
return;
posLeft += (this.showGutter ? this.$gutterLayer.gutterWidth : 0) - this.scrollLeft;
var bounds = this.container.getBoundingClientRect();
this.textarea.style.left = (bounds.left + posLeft) + "px";
this.textarea.style.top = (bounds.top + posTop) + "px";
var w = this.characterWidth;
if (this.$composition)
w += this.textarea.scrollWidth;
posLeft -= this.scrollLeft;
if (posLeft > this.$size.scrollerWidth - w)
posLeft = this.$size.scrollerWidth - w;
if (this.showGutter)
posLeft += this.$gutterLayer.gutterWidth;
this.textarea.style.height = this.lineHeight + "px";
this.textarea.style.width = w + "px";
this.textarea.style.left = posLeft + "px";
this.textarea.style.top = posTop - 1 + "px";
};
/**
@ -657,13 +673,15 @@ var VirtualRenderer = function(container, theme) {
// update scrollbar first to not lose scroll position when gutter calls resize
this.$updateScrollBar();
this.$textLayer.update(this.layerConfig);
if (this.showGutter)
if (this.showGutter) {
if (this.$highlightGutterLine)
this.$updateGutterLineHighlight(true);
this.$gutterLayer.update(this.layerConfig);
}
this.$markerBack.update(this.layerConfig);
this.$markerFront.update(this.layerConfig);
this.$cursorLayer.update(this.layerConfig);
this.$moveTextAreaToCursor();
this.$highlightGutterLine && this.$updateGutterLineHighlight();
return;
}
@ -675,13 +693,15 @@ var VirtualRenderer = function(container, theme) {
else
this.$textLayer.scrollLines(this.layerConfig);
if (this.showGutter)
if (this.showGutter) {
if (this.$highlightGutterLine)
this.$updateGutterLineHighlight(true);
this.$gutterLayer.update(this.layerConfig);
}
this.$markerBack.update(this.layerConfig);
this.$markerFront.update(this.layerConfig);
this.$cursorLayer.update(this.layerConfig);
this.$moveTextAreaToCursor();
this.$highlightGutterLine && this.$updateGutterLineHighlight();
return;
}
@ -704,7 +724,7 @@ var VirtualRenderer = function(container, theme) {
if (changes & this.CHANGE_CURSOR) {
this.$cursorLayer.update(this.layerConfig);
this.$moveTextAreaToCursor();
this.$highlightGutterLine && this.$updateGutterLineHighlight();
this.$highlightGutterLine && this.$updateGutterLineHighlight(false);
}
if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_FRONT)) {
@ -800,10 +820,6 @@ var VirtualRenderer = function(container, theme) {
var layerConfig = this.layerConfig;
// if the update changes the width of the document do a full redraw
if (layerConfig.width != this.$getLongestLine())
return this.$textLayer.update(layerConfig);
if (firstRow > layerConfig.lastRow + 1) { return; }
if (lastRow < layerConfig.firstRow) { return; }
@ -873,13 +889,11 @@ var VirtualRenderer = function(container, theme) {
};
/**
* VirtualRenderer.setBreakpoints(rows) -> Void
* - rows (Array): An array containg row numbers
* VirtualRenderer.updateBreakpoints() -> Void
*
* Sets a breakpoint for every row number indicated on `rows`.
* Redraw breakpoints.
**/
this.setBreakpoints = function(rows) {
this.$gutterLayer.setBreakpoints(rows);
this.updateBreakpoints = function(rows) {
this.$loop.schedule(this.CHANGE_GUTTER);
};
@ -1035,13 +1049,13 @@ var VirtualRenderer = function(container, theme) {
return steps;
};
/**
/**
* VirtualRenderer.scrollToLine(line, center, animate, callback) -> Void
* - line (Number): A line number
* - center (Boolean): If `true`, centers the editor the to indicated line
* - animate (Boolean): If `true` animates scrolling
* - callback (Function): Function to be called after the animation has finished
*
*
* Gracefully scrolls the editor to the row indicated.
**/
this.scrollToLine = function(line, center, animate, callback) {
@ -1062,7 +1076,7 @@ var VirtualRenderer = function(container, theme) {
var _self = this;
var steps = _self.$calcSteps(fromValue, toValue);
this.$inScrollAnimation = true;
clearInterval(this.$timer);
_self.session.setScrollTop(steps.shift());
@ -1071,18 +1085,20 @@ var VirtualRenderer = function(container, theme) {
_self.session.setScrollTop(steps.shift());
// trick session to think it's already scrolled to not loose toValue
_self.session.$scrollTop = toValue;
} else {
_self.$inScrollAnimation = false;
clearInterval(_self.$timer);
} else if (toValue != null) {
_self.session.$scrollTop = -1;
_self.session.setScrollTop(toValue);
toValue = null;
} else {
// do this on separate step to not get spurious scroll event from scrollbar
_self.$timer = clearInterval(_self.$timer);
_self.$inScrollAnimation = false;
callback && callback();
}
}, 10);
}
};
/**
* VirtualRenderer.scrollToY(scrollTop) -> Number
* - scrollTop (Number): The position to scroll to
@ -1211,21 +1227,16 @@ var VirtualRenderer = function(container, theme) {
*
**/
this.showComposition = function(position) {
if (!this.$composition) {
this.$composition = dom.createElement("div");
this.$composition.className = "ace_composition";
this.content.appendChild(this.$composition);
}
if (!this.$composition)
this.$composition = {
keepTextAreaAtCursor: this.$keepTextAreaAtCursor,
cssText: this.textarea.style.cssText
};
this.$composition.innerHTML = "&#160;";
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";
this.hideCursor();
this.$keepTextAreaAtCursor = true;
dom.addCssClass(this.textarea, "ace_composition");
this.textarea.style.cssText = "";
this.$moveTextAreaToCursor();
};
/**
@ -1235,7 +1246,7 @@ var VirtualRenderer = function(container, theme) {
* Sets the inner text of the current composition to `text`.
**/
this.setCompositionText = function(text) {
dom.setInnerText(this.$composition, text);
this.$moveTextAreaToCursor();
};
/**
@ -1244,14 +1255,13 @@ var VirtualRenderer = function(container, theme) {
* Hides the current composition.
**/
this.hideComposition = function() {
this.showCursor();
if (!this.$composition)
return;
var style = this.$composition.style;
style.top = "-10000px";
style.left = "-10000px";
dom.removeCssClass(this.textarea, "ace_composition");
this.$keepTextAreaAtCursor = this.$composition.keepTextAreaAtCursor;
this.textarea.style.cssText = this.$composition.cssText;
this.$composition = null;
};
this._loadTheme = function(name, callback) {