commit
9d4faf8911
9 changed files with 673 additions and 10 deletions
|
|
@ -66,6 +66,8 @@ var bindDropdown = util.bindDropdown;
|
|||
|
||||
var ElasticTabstopsLite = require("ace/ext/elastic_tabstops_lite").ElasticTabstopsLite;
|
||||
|
||||
var IncrementalSearch = require("ace/incremental_search").IncrementalSearch;
|
||||
|
||||
/*********** create editor ***************************/
|
||||
var container = document.getElementById("editor-container");
|
||||
|
||||
|
|
@ -173,7 +175,7 @@ commands.addCommand({
|
|||
exec: function() {alert("Fake Save File");}
|
||||
});
|
||||
|
||||
var keybindings = {
|
||||
var keybindings = {
|
||||
ace: null, // Null = use "default" keymapping
|
||||
vim: require("ace/keyboard/vim").handler,
|
||||
emacs: "ace/keyboard/emacs",
|
||||
|
|
@ -380,7 +382,7 @@ bindDropdown("split", function(value) {
|
|||
sp.setSplits(1);
|
||||
} else {
|
||||
var newEditor = (sp.getSplits() == 1);
|
||||
sp.setOrientation(value == "below" ? sp.BELOW : sp.BESIDE);
|
||||
sp.setOrientation(value == "below" ? sp.BELOW : sp.BESIDE);
|
||||
sp.setSplits(2);
|
||||
|
||||
if (newEditor) {
|
||||
|
|
@ -396,6 +398,14 @@ bindCheckbox("elastic_tabstops", function(checked) {
|
|||
env.editor.setOption("useElasticTabstops", checked);
|
||||
});
|
||||
|
||||
var iSearchCheckbox = bindCheckbox("isearch", function(checked) {
|
||||
env.editor.setOption("useIncrementalSearch", checked);
|
||||
});
|
||||
|
||||
env.editor.addEventListener('incrementalSearchSettingChanged', function(event) {
|
||||
iSearchCheckbox.checked = event.isEnabled;
|
||||
});
|
||||
|
||||
|
||||
function synchroniseScrolling() {
|
||||
var s1 = env.split.$editors[0].session;
|
||||
|
|
@ -451,4 +461,3 @@ var StatusBar = require("./statusbar").StatusBar;
|
|||
new StatusBar(env.editor, cmdLine.container);
|
||||
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ exports.bindCheckbox = function(id, callback, noInit) {
|
|||
};
|
||||
el.onclick = onCheck;
|
||||
noInit || onCheck();
|
||||
return el;
|
||||
};
|
||||
|
||||
exports.bindDropdown = function(id, callback, noInit) {
|
||||
|
|
@ -235,4 +236,3 @@ function dropdown(values) {
|
|||
|
||||
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -250,6 +250,14 @@
|
|||
<input type="checkbox" id="elastic_tabstops">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >
|
||||
<label for="isearch">Incremental Search</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" id="isearch">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td >
|
||||
<label for="highlight_token">Show token info</label>
|
||||
|
|
|
|||
172
lib/ace/commands/incremental_search_commands.js
Normal file
172
lib/ace/commands/incremental_search_commands.js
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var config = require("../config");
|
||||
|
||||
// These commands can be installed in a normal key handler to start iSearch:
|
||||
exports.iSearchStartCommands = [{
|
||||
name: "iSearch",
|
||||
bindKey: {win: "Ctrl-F", mac: "Command-F"},
|
||||
exec: function(editor, options) {
|
||||
config.loadModule(["core", "ace/incremental_search"], function(e) {
|
||||
var iSearch = e.iSearch = e.iSearch || new e.IncrementalSearch();
|
||||
iSearch.activate(editor, options.backwards);
|
||||
if (options.jumpToFirstMatch) iSearch.next(options);
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "iSearchBackwards",
|
||||
exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {backwards: true}); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "iSearchAndGo",
|
||||
bindKey: {win: "Ctrl-K", mac: "Command-G"},
|
||||
exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {jumpToFirstMatch: true, useCurrentOrPrevSearch: true}); },
|
||||
readOnly: true
|
||||
}, {
|
||||
name: "iSearchBackwardsAndGo",
|
||||
bindKey: {win: "Ctrl-Shift-K", mac: "Command-Shift-G"},
|
||||
exec: function(editor) { editor.execCommand('iSearch', {jumpToFirstMatch: true, backwards: true, useCurrentOrPrevSearch: true}); },
|
||||
readOnly: true
|
||||
}];
|
||||
|
||||
// These commands are only available when incremental search mode is active:
|
||||
exports.iSearchCommands = [{
|
||||
name: "restartSearch",
|
||||
bindKey: {win: "Ctrl-F", mac: "Command-F"},
|
||||
exec: function(iSearch) {
|
||||
iSearch.cancelSearch(true);
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "searchForward",
|
||||
bindKey: {win: "Ctrl-S|Ctrl-K", mac: "Ctrl-S|Command-G"},
|
||||
exec: function(iSearch, options) {
|
||||
options.useCurrentOrPrevSearch = true;
|
||||
iSearch.next(options);
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "searchBackward",
|
||||
bindKey: {win: "Ctrl-R|Ctrl-Shift-K", mac: "Ctrl-R|Command-Shift-G"},
|
||||
exec: function(iSearch, options) {
|
||||
options.useCurrentOrPrevSearch = true;
|
||||
options.backwards = true;
|
||||
iSearch.next(options);
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "extendSearchTerm",
|
||||
exec: function(iSearch, string) {
|
||||
iSearch.addChar(string);
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "extendSearchTermSpace",
|
||||
bindKey: "space",
|
||||
exec: function(iSearch) { iSearch.addChar(' '); },
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: "shrinkSearchTerm",
|
||||
bindKey: "backspace",
|
||||
exec: function(iSearch) {
|
||||
iSearch.removeChar();
|
||||
},
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: 'confirmSearch',
|
||||
bindKey: 'return',
|
||||
exec: function(iSearch) { iSearch.deactivate(); },
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}, {
|
||||
name: 'cancelSearch',
|
||||
bindKey: 'esc|Ctrl-G',
|
||||
exec: function(iSearch) { iSearch.deactivate(true); },
|
||||
readOnly: true,
|
||||
isIncrementalSearchCommand: true
|
||||
}];
|
||||
|
||||
|
||||
|
||||
var HashHandler = require("../keyboard/hash_handler").HashHandler;
|
||||
var oop = require("../lib/oop");
|
||||
|
||||
function IncrementalSearchKeyboardHandler(iSearch) {
|
||||
this.$iSearch = iSearch;
|
||||
}
|
||||
|
||||
oop.inherits(IncrementalSearchKeyboardHandler, HashHandler);
|
||||
|
||||
;(function() {
|
||||
|
||||
this.attach = function(editor) {
|
||||
var iSearch = this.$iSearch;
|
||||
HashHandler.call(this, exports.iSearchCommands, editor.commands.platform);
|
||||
this.$commandExecHandler = editor.commands.addEventListener('exec', function(e) {
|
||||
if (!e.command.isIncrementalSearchCommand) return undefined;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return e.command.exec(iSearch, e.args || {});
|
||||
});
|
||||
}
|
||||
|
||||
this.detach = function(editor) {
|
||||
if (!this.$commandExecHandler) return;
|
||||
editor.commands.removeEventListener('exec', this.$commandExecHandler);
|
||||
delete this.$commandExecHandler;
|
||||
}
|
||||
|
||||
var handleKeyboard$super = this.handleKeyboard;
|
||||
this.handleKeyboard = function(data, hashId, key, keyCode) {
|
||||
var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode);
|
||||
if (cmd.command) { return cmd; }
|
||||
if (hashId == -1) {
|
||||
var extendCmd = this.commands.extendSearchTerm;
|
||||
if (extendCmd) { return {command: extendCmd, args: key}; }
|
||||
}
|
||||
return {command: "null", passEvent: hashId == 0 || hashId == 4};
|
||||
}
|
||||
|
||||
}).call(IncrementalSearchKeyboardHandler.prototype);
|
||||
|
||||
|
||||
exports.IncrementalSearchKeyboardHandler = IncrementalSearchKeyboardHandler;
|
||||
|
||||
});
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
|
|
|
|||
257
lib/ace/incremental_search.js
Normal file
257
lib/ace/incremental_search.js
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("./lib/oop");
|
||||
var Range = require("./range").Range;
|
||||
var Search = require("./search").Search;
|
||||
var SearchHighlight = require("./search_highlight").SearchHighlight;
|
||||
var iSearchCommandModule = require("./commands/incremental_search_commands");
|
||||
var ISearchKbd = iSearchCommandModule.IncrementalSearchKeyboardHandler;
|
||||
|
||||
/**
|
||||
* @class IncrementalSearch
|
||||
*
|
||||
* Implements immediate searching while the user is typing. When incremental
|
||||
* search is activated, keystrokes into the editor will be used for composing
|
||||
* a search term. Immediately after every keystroke the search is updated:
|
||||
* - so-far-matching characters are highlighted
|
||||
* - the cursor is moved to the next match
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Creates a new `IncrementalSearch` object.
|
||||
*
|
||||
* @constructor
|
||||
**/
|
||||
function IncrementalSearch() {
|
||||
this.$options = {wrap: false, skipCurrent: false};
|
||||
this.$keyboardHandler = new ISearchKbd(this);
|
||||
}
|
||||
|
||||
oop.inherits(IncrementalSearch, Search);
|
||||
|
||||
;(function() {
|
||||
|
||||
this.activate = function(ed, backwards) {
|
||||
this.$editor = ed;
|
||||
this.$startPos = this.$currentPos = ed.getCursorPosition();
|
||||
this.$options.needle = '';
|
||||
this.$options.backwards = backwards;
|
||||
ed.keyBinding.addKeyboardHandler(this.$keyboardHandler);
|
||||
this.$mousedownHandler = ed.addEventListener('mousedown', this.onMouseDown.bind(this));
|
||||
this.selectionFix(ed);
|
||||
this.statusMessage(true);
|
||||
}
|
||||
|
||||
this.deactivate = function(reset) {
|
||||
this.cancelSearch(reset);
|
||||
this.$editor.keyBinding.removeKeyboardHandler(this.$keyboardHandler);
|
||||
if (this.$mousedownHandler) {
|
||||
this.$editor.removeEventListener('mousedown', this.$mousedownHandler);
|
||||
delete this.$mousedownHandler;
|
||||
}
|
||||
this.message('');
|
||||
}
|
||||
|
||||
this.selectionFix = function(editor) {
|
||||
// Fix selection bug: When clicked inside the editor
|
||||
// editor.selection.$isEmpty is false even if the mouse click did not
|
||||
// open a selection. This is interpreted by the move commands to
|
||||
// extend the selection. To only extend the selection when there is
|
||||
// one, we clear it here
|
||||
if (editor.selection.isEmpty() && !editor.session.$emacsMark) {
|
||||
editor.clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
this.highlight = function(regexp) {
|
||||
var sess = this.$editor.session,
|
||||
hl = sess.$isearchHighlight = sess.$isearchHighlight || sess.addDynamicMarker(
|
||||
new SearchHighlight(null, "ace_isearch-result", "text"));
|
||||
hl.setRegexp(regexp);
|
||||
sess._emit("changeBackMarker"); // force highlight layer redraw
|
||||
}
|
||||
|
||||
this.cancelSearch = function(reset) {
|
||||
var e = this.$editor;
|
||||
this.$prevNeedle = this.$options.needle;
|
||||
this.$options.needle = '';
|
||||
if (reset) {
|
||||
e.moveCursorToPosition(this.$startPos);
|
||||
this.$currentPos = this.$startPos;
|
||||
}
|
||||
this.highlight(null);
|
||||
return Range.fromPoints(this.$currentPos, this.$currentPos);
|
||||
}
|
||||
|
||||
this.highlightAndFindWithNeedle = function(moveToNext, needleUpdateFunc) {
|
||||
if (!this.$editor) return null;
|
||||
var options = this.$options;
|
||||
|
||||
// get search term
|
||||
if (needleUpdateFunc) {
|
||||
options.needle = needleUpdateFunc.call(this, options.needle || '') || '';
|
||||
}
|
||||
if (options.needle.length === 0) {
|
||||
this.statusMessage(true);
|
||||
return this.cancelSearch(true);
|
||||
};
|
||||
|
||||
// try to find the next occurence and enable highlighting marker
|
||||
options.start = this.$currentPos;
|
||||
var session = this.$editor.session,
|
||||
found = this.find(session);
|
||||
if (found) {
|
||||
if (options.backwards) found = Range.fromPoints(found.end, found.start);
|
||||
this.$editor.moveCursorToPosition(found.end);
|
||||
if (moveToNext) this.$currentPos = found.end;
|
||||
// highlight after cursor move, so selection works properly
|
||||
this.highlight(options.re)
|
||||
}
|
||||
|
||||
this.statusMessage(found);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
this.addChar = function(c) {
|
||||
return this.highlightAndFindWithNeedle(false, function(needle) {
|
||||
return needle + c;
|
||||
});
|
||||
}
|
||||
|
||||
this.removeChar = function(c) {
|
||||
return this.highlightAndFindWithNeedle(false, function(needle) {
|
||||
return needle.length > 0 ? needle.substring(0, needle.length-1) : needle;
|
||||
});
|
||||
}
|
||||
|
||||
this.next = function(options) {
|
||||
// try to find the next occurence of whatever we have searched for
|
||||
// earlier.
|
||||
// options = {[backwards: BOOL], [useCurrentOrPrevSearch: BOOL]}
|
||||
options = options || {};
|
||||
this.$options.backwards = !!options.backwards;
|
||||
this.$currentPos = this.$editor.getCursorPosition();
|
||||
return this.highlightAndFindWithNeedle(true, function(needle) {
|
||||
return options.useCurrentOrPrevSearch && needle.length === 0 ?
|
||||
this.$prevNeedle || '' : needle;
|
||||
});
|
||||
}
|
||||
|
||||
this.onMouseDown = function(evt) {
|
||||
// when mouse interaction happens then we quit incremental search
|
||||
this.deactivate();
|
||||
return true;
|
||||
}
|
||||
|
||||
this.statusMessage = function(found) {
|
||||
var options = this.$options, msg = '';
|
||||
msg += options.backwards ? 'reverse-' : '';
|
||||
msg += 'isearch: ' + options.needle;
|
||||
msg += found ? '' : ' (not found)';
|
||||
this.message(msg);
|
||||
}
|
||||
|
||||
this.message = function(msg) {
|
||||
if (this.$editor.showCommandLine) {
|
||||
this.$editor.showCommandLine(msg);
|
||||
this.$editor.focus();
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}).call(IncrementalSearch.prototype);
|
||||
|
||||
|
||||
exports.IncrementalSearch = IncrementalSearch;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Config settings for enabling/disabling [[IncrementalSearch `IncrementalSearch`]].
|
||||
*
|
||||
**/
|
||||
|
||||
var dom = require('./lib/dom');
|
||||
dom.importCssString && dom.importCssString("\
|
||||
.ace_marker-layer .ace_isearch-result {\
|
||||
position: absolute;\
|
||||
z-index: 6;\
|
||||
-moz-box-sizing: border-box;\
|
||||
-webkit-box-sizing: border-box;\
|
||||
box-sizing: border-box;\
|
||||
}\
|
||||
div.ace_isearch-result {\
|
||||
border-radius: 4px;\
|
||||
border: 8px solid rgba(255, 200, 0, 0.5);\
|
||||
box-shadow: 0 0 4px rgb(255, 200, 0);\
|
||||
}\
|
||||
.ace_dark div.ace_isearch-result {\
|
||||
border: 8px solid rgb(100, 110, 160);\
|
||||
box-shadow: 0 0 4px rgb(80, 90, 140);\
|
||||
}", "incremental-search-highlighting");
|
||||
|
||||
// support for default keyboard handler
|
||||
var commands = require("./commands/command_manager");
|
||||
(function() {
|
||||
this.setupIncrementalSearch = function(editor, val) {
|
||||
if (this.usesIncrementalSearch == val) return;
|
||||
this.usesIncrementalSearch = val;
|
||||
var iSearchCommands = iSearchCommandModule.iSearchStartCommands;
|
||||
var method = val ? 'addCommands' : 'removeCommands';
|
||||
this[method](iSearchCommands);
|
||||
};
|
||||
}).call(commands.CommandManager.prototype);
|
||||
|
||||
// incremental search config option
|
||||
var Editor = require("./editor").Editor;
|
||||
require("./config").defineOptions(Editor.prototype, "editor", {
|
||||
useIncrementalSearch: {
|
||||
set: function(val) {
|
||||
this.keyBinding.$handlers.forEach(function(handler) {
|
||||
if (handler.setupIncrementalSearch) {
|
||||
handler.setupIncrementalSearch(this, val);
|
||||
}
|
||||
});
|
||||
this._emit('incrementalSearchSettingChanged', {isEnabled: val});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
208
lib/ace/incremental_search_test.js
Normal file
208
lib/ace/incremental_search_test.js
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
if (typeof process !== "undefined") {
|
||||
require("amd-loader");
|
||||
}
|
||||
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var EditSession = require("./edit_session").EditSession;
|
||||
var Editor = require("./editor").Editor;
|
||||
var MockRenderer = require("./test/mockrenderer").MockRenderer;
|
||||
var Range = require("./range").Range;
|
||||
var assert = require("./test/assertions");
|
||||
var IncrementalSearch = require("./incremental_search").IncrementalSearch;
|
||||
|
||||
var editor, iSearch;
|
||||
function testRanges(str, ranges) {
|
||||
ranges = ranges || editor.selection.getAllRanges();
|
||||
assert.equal(ranges + "", str + "");
|
||||
}
|
||||
|
||||
// force "rerender"
|
||||
function callHighlighterUpdate() {
|
||||
var session = editor.session,
|
||||
ranges = [],
|
||||
mockMarkerLayer = {
|
||||
drawSingleLineMarker: function(_, markerRanges) {
|
||||
ranges = ranges.concat(markerRanges);
|
||||
}
|
||||
}
|
||||
session.$isearchHighlight.update([], mockMarkerLayer, session, {
|
||||
firstRow: 0, lastRow: session.getRowLength()});
|
||||
return ranges;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
name: "ACE incremental_search.js",
|
||||
|
||||
setUp: function() {
|
||||
var session = new EditSession(["abc123", "xyz124"]);
|
||||
editor = new Editor(new MockRenderer(), session);
|
||||
iSearch = new IncrementalSearch();
|
||||
},
|
||||
|
||||
"test: keyboard handler setup" : function() {
|
||||
iSearch.activate(editor);
|
||||
assert.equal(editor.getKeyboardHandler(), iSearch.$keyboardHandler);
|
||||
iSearch.deactivate();
|
||||
assert.notEqual(editor.getKeyboardHandler(), iSearch.$keyboardHandler);
|
||||
},
|
||||
|
||||
"test: isearch highlight setup" : function() {
|
||||
var sess = editor.session;
|
||||
iSearch.activate(editor);
|
||||
iSearch.highlight('foo');
|
||||
var highl = sess.$isearchHighlight.id;
|
||||
assert.ok(sess.$isearchHighlight, 'session has no isearch highlighter');
|
||||
assert.equal(sess.getMarkers()[highl.id], highl.id, 'isearch highlight not in markers');
|
||||
iSearch.deactivate();
|
||||
iSearch.activate(editor);
|
||||
iSearch.highlight('bar');
|
||||
var highl2 = sess.$isearchHighlight.id;
|
||||
assert.equal(highl2, highl, 'multiple isearch highlights');
|
||||
},
|
||||
|
||||
"test: find simple text incrementally" : function() {
|
||||
iSearch.activate(editor);
|
||||
var range = iSearch.addChar('1'), // "1"
|
||||
highlightRanges = callHighlighterUpdate(editor.session);
|
||||
testRanges("Range: [0/3] -> [0/4]", [range], "range");
|
||||
testRanges("Range: [0/3] -> [0/4],Range: [1/3] -> [1/4]", highlightRanges, "highlight");
|
||||
|
||||
range = iSearch.addChar('2'); // "12"
|
||||
highlightRanges = callHighlighterUpdate(editor.session);
|
||||
testRanges("Range: [0/3] -> [0/5]", [range], "range");
|
||||
testRanges("Range: [0/3] -> [0/5],Range: [1/3] -> [1/5]", highlightRanges, "highlight");
|
||||
|
||||
range = iSearch.addChar('3'); // "123"
|
||||
highlightRanges = callHighlighterUpdate(editor.session);
|
||||
testRanges("Range: [0/3] -> [0/6]", [range], "range");
|
||||
testRanges("Range: [0/3] -> [0/6]", highlightRanges, "highlight");
|
||||
|
||||
range = iSearch.removeChar(); // "12"
|
||||
highlightRanges = callHighlighterUpdate(editor.session);
|
||||
testRanges("Range: [0/3] -> [0/5]", [range], "range");
|
||||
testRanges("Range: [0/3] -> [0/5],Range: [1/3] -> [1/5]", highlightRanges, "highlight");
|
||||
},
|
||||
|
||||
"test: forward / backward" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addChar('1'); iSearch.addChar('2');
|
||||
var range = iSearch.next();
|
||||
testRanges("Range: [1/3] -> [1/5]", [range], "range");
|
||||
|
||||
range = iSearch.next(); // nothing to find
|
||||
testRanges("", [range], "range");
|
||||
|
||||
range = iSearch.next({backwards: true}); // backwards
|
||||
testRanges("Range: [1/5] -> [1/3]", [range], "range");
|
||||
},
|
||||
|
||||
"test: cancelSearch" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addChar('1'); iSearch.addChar('2');
|
||||
var range = iSearch.cancelSearch(true);
|
||||
testRanges("Range: [0/0] -> [0/0]", [range], "range");
|
||||
|
||||
iSearch.addChar('1'); range = iSearch.addChar('2');
|
||||
testRanges("Range: [0/3] -> [0/5]", [range], "range");
|
||||
},
|
||||
|
||||
"test: failing search keeps pos" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addChar('1'); iSearch.addChar('2');
|
||||
var range = iSearch.addChar('x');
|
||||
testRanges("", [range], "range");
|
||||
assert.position(editor.getCursorPosition(), 0, 5);
|
||||
},
|
||||
|
||||
"test: backwards search" : function() {
|
||||
editor.moveCursorTo(1,0);
|
||||
iSearch.activate(editor, true);
|
||||
iSearch.addChar('1'); var range = iSearch.addChar('2');;
|
||||
testRanges("Range: [0/5] -> [0/3]", [range], "range");
|
||||
assert.position(editor.getCursorPosition(), 0, 3);
|
||||
},
|
||||
|
||||
"test: forwards then backwards, same result, reoriented range" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addChar('1'); var range = iSearch.addChar('2');;
|
||||
testRanges("Range: [0/3] -> [0/5]", [range], "range");
|
||||
assert.position(editor.getCursorPosition(), 0, 5);
|
||||
|
||||
range = iSearch.next({backwards: true});
|
||||
testRanges("Range: [0/5] -> [0/3]", [range], "range");
|
||||
assert.position(editor.getCursorPosition(), 0, 3);
|
||||
},
|
||||
|
||||
"test: reuse prev search via option" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addChar('1'); iSearch.addChar('2');;
|
||||
assert.position(editor.getCursorPosition(), 0, 5);
|
||||
iSearch.deactivate();
|
||||
|
||||
iSearch.activate(editor);
|
||||
iSearch.next({backwards: false, useCurrentOrPrevSearch: true});
|
||||
assert.position(editor.getCursorPosition(), 1, 5);
|
||||
},
|
||||
|
||||
"test: don't extend selection range if selection is empty" : function() {
|
||||
iSearch.activate(editor);
|
||||
iSearch.addChar('1'); iSearch.addChar('2');;
|
||||
testRanges("Range: [0/5] -> [0/5]", [editor.getSelectionRange()], "sel range");
|
||||
},
|
||||
|
||||
"test: extend selection range if selection exists" : function() {
|
||||
iSearch.activate(editor);
|
||||
editor.selection.selectTo(0, 1);
|
||||
iSearch.addChar('1'); iSearch.addChar('2');;
|
||||
testRanges("Range: [0/0] -> [0/5]", [editor.getSelectionRange()], "sel range");
|
||||
},
|
||||
|
||||
"test: extend selection in emacs mark mode" : function() {
|
||||
var emacs = require('./keyboard/emacs');
|
||||
editor.keyBinding.addKeyboardHandler(emacs.handler);
|
||||
emacs.handler.commands.setMark.exec(editor);
|
||||
iSearch.activate(editor);
|
||||
iSearch.addChar('1'); iSearch.addChar('2');;
|
||||
testRanges("Range: [0/0] -> [0/5]", [editor.getSelectionRange()], "sel range");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if (typeof module !== "undefined" && module === require.main) {
|
||||
require("asyncjs").test.testcase(module.exports).exec()
|
||||
}
|
||||
|
|
@ -32,6 +32,9 @@ define(function(require, exports, module) {
|
|||
"use strict";
|
||||
|
||||
var dom = require("../lib/dom");
|
||||
require("../incremental_search");
|
||||
var iSearchCommandModule = require("../commands/incremental_search_commands");
|
||||
|
||||
|
||||
var screenToTextBlockCoordinates = function(x, y) {
|
||||
var canvasPos = this.scroller.getBoundingClientRect();
|
||||
|
|
@ -49,6 +52,8 @@ var screenToTextBlockCoordinates = function(x, y) {
|
|||
var HashHandler = require("./hash_handler").HashHandler;
|
||||
exports.handler = new HashHandler();
|
||||
|
||||
exports.handler.isEmacs = true
|
||||
|
||||
var initialized = false;
|
||||
var $formerLongWords;
|
||||
var $formerLineStart;
|
||||
|
|
@ -100,7 +105,7 @@ exports.handler.attach = function(editor) {
|
|||
}
|
||||
|
||||
editor.on("click", $resetMarkMode);
|
||||
editor.on("changeSession",$kbSessionChange);
|
||||
editor.on("changeSession", $kbSessionChange);
|
||||
editor.renderer.screenToTextCoordinates = screenToTextBlockCoordinates;
|
||||
editor.setStyle("emacs-mode");
|
||||
editor.commands.addCommands(commands);
|
||||
|
|
@ -296,8 +301,10 @@ exports.emacsKeys = {
|
|||
"PageUp|M-v": {command: "goorselect", args: ["gotopageup","selectpageup"]},
|
||||
"S-C-Down": "selectpagedown",
|
||||
"S-C-Up": "selectpageup",
|
||||
"C-s": "findnext",
|
||||
"C-r": "findprevious",
|
||||
|
||||
"C-s": "iSearch",
|
||||
"C-r": "iSearchBackwards",
|
||||
|
||||
"M-C-s": "findnext",
|
||||
"M-C-r": "findprevious",
|
||||
"S-M-5": "replace",
|
||||
|
|
@ -457,6 +464,8 @@ exports.handler.addCommands({
|
|||
}
|
||||
});
|
||||
|
||||
exports.handler.addCommands(iSearchCommandModule.iSearchStartCommands);
|
||||
|
||||
var commands = exports.handler.commands;
|
||||
commands.yank.isYank = true;
|
||||
commands.yankRotate.isYank = true;
|
||||
|
|
@ -482,5 +491,4 @@ exports.killRing = {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ var testNames = [
|
|||
"ace/editor_navigation_test",
|
||||
"ace/editor_text_edit_test",
|
||||
"ace/ext/static_highlight_test",
|
||||
"ace/incremental_search_test",
|
||||
"ace/keyboard/emacs_test",
|
||||
"ace/keyboard/keybinding_test",
|
||||
"ace/layer/text_test",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue