incremental_search_commands.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Distributed under the BSD license:
  3. *
  4. * Copyright (c) 2010, Ajax.org B.V.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * * Neither the name of Ajax.org B.V. nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. * ***** END LICENSE BLOCK ***** */
  30. define(function(require, exports, module) {
  31. var config = require("../config");
  32. var oop = require("../lib/oop");
  33. var HashHandler = require("../keyboard/hash_handler").HashHandler;
  34. var occurStartCommand = require("./occur_commands").occurStartCommand;
  35. // These commands can be installed in a normal key handler to start iSearch:
  36. exports.iSearchStartCommands = [{
  37. name: "iSearch",
  38. bindKey: {win: "Ctrl-F", mac: "Command-F"},
  39. exec: function(editor, options) {
  40. config.loadModule(["core", "ace/incremental_search"], function(e) {
  41. var iSearch = e.iSearch = e.iSearch || new e.IncrementalSearch();
  42. iSearch.activate(editor, options.backwards);
  43. if (options.jumpToFirstMatch) iSearch.next(options);
  44. });
  45. },
  46. readOnly: true
  47. }, {
  48. name: "iSearchBackwards",
  49. exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {backwards: true}); },
  50. readOnly: true
  51. }, {
  52. name: "iSearchAndGo",
  53. bindKey: {win: "Ctrl-K", mac: "Command-G"},
  54. exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {jumpToFirstMatch: true, useCurrentOrPrevSearch: true}); },
  55. readOnly: true
  56. }, {
  57. name: "iSearchBackwardsAndGo",
  58. bindKey: {win: "Ctrl-Shift-K", mac: "Command-Shift-G"},
  59. exec: function(editor) { editor.execCommand('iSearch', {jumpToFirstMatch: true, backwards: true, useCurrentOrPrevSearch: true}); },
  60. readOnly: true
  61. }];
  62. // These commands are only available when incremental search mode is active:
  63. exports.iSearchCommands = [{
  64. name: "restartSearch",
  65. bindKey: {win: "Ctrl-F", mac: "Command-F"},
  66. exec: function(iSearch) {
  67. iSearch.cancelSearch(true);
  68. }
  69. }, {
  70. name: "searchForward",
  71. bindKey: {win: "Ctrl-S|Ctrl-K", mac: "Ctrl-S|Command-G"},
  72. exec: function(iSearch, options) {
  73. options.useCurrentOrPrevSearch = true;
  74. iSearch.next(options);
  75. }
  76. }, {
  77. name: "searchBackward",
  78. bindKey: {win: "Ctrl-R|Ctrl-Shift-K", mac: "Ctrl-R|Command-Shift-G"},
  79. exec: function(iSearch, options) {
  80. options.useCurrentOrPrevSearch = true;
  81. options.backwards = true;
  82. iSearch.next(options);
  83. }
  84. }, {
  85. name: "extendSearchTerm",
  86. exec: function(iSearch, string) {
  87. iSearch.addString(string);
  88. }
  89. }, {
  90. name: "extendSearchTermSpace",
  91. bindKey: "space",
  92. exec: function(iSearch) { iSearch.addString(' '); }
  93. }, {
  94. name: "shrinkSearchTerm",
  95. bindKey: "backspace",
  96. exec: function(iSearch) {
  97. iSearch.removeChar();
  98. }
  99. }, {
  100. name: 'confirmSearch',
  101. bindKey: 'return',
  102. exec: function(iSearch) { iSearch.deactivate(); }
  103. }, {
  104. name: 'cancelSearch',
  105. bindKey: 'esc|Ctrl-G',
  106. exec: function(iSearch) { iSearch.deactivate(true); }
  107. }, {
  108. name: 'occurisearch',
  109. bindKey: 'Ctrl-O',
  110. exec: function(iSearch) {
  111. var options = oop.mixin({}, iSearch.$options);
  112. iSearch.deactivate();
  113. occurStartCommand.exec(iSearch.$editor, options);
  114. }
  115. }, {
  116. name: "yankNextWord",
  117. bindKey: "Ctrl-w",
  118. exec: function(iSearch) {
  119. var ed = iSearch.$editor,
  120. range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorWordRight(); }),
  121. string = ed.session.getTextRange(range);
  122. iSearch.addString(string);
  123. }
  124. }, {
  125. name: "yankNextChar",
  126. bindKey: "Ctrl-Alt-y",
  127. exec: function(iSearch) {
  128. var ed = iSearch.$editor,
  129. range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorRight(); }),
  130. string = ed.session.getTextRange(range);
  131. iSearch.addString(string);
  132. }
  133. }, {
  134. name: 'recenterTopBottom',
  135. bindKey: 'Ctrl-l',
  136. exec: function(iSearch) { iSearch.$editor.execCommand('recenterTopBottom'); }
  137. }, {
  138. name: 'selectAllMatches',
  139. bindKey: 'Ctrl-space',
  140. exec: function(iSearch) {
  141. var ed = iSearch.$editor,
  142. hl = ed.session.$isearchHighlight,
  143. ranges = hl && hl.cache ? hl.cache
  144. .reduce(function(ranges, ea) {
  145. return ranges.concat(ea ? ea : []); }, []) : [];
  146. iSearch.deactivate(false);
  147. ranges.forEach(ed.selection.addRange.bind(ed.selection));
  148. }
  149. }, {
  150. name: 'searchAsRegExp',
  151. bindKey: 'Alt-r',
  152. exec: function(iSearch) {
  153. iSearch.convertNeedleToRegExp();
  154. }
  155. }].map(function(cmd) {
  156. cmd.readOnly = true;
  157. cmd.isIncrementalSearchCommand = true;
  158. cmd.scrollIntoView = "animate-cursor";
  159. return cmd;
  160. });
  161. function IncrementalSearchKeyboardHandler(iSearch) {
  162. this.$iSearch = iSearch;
  163. }
  164. oop.inherits(IncrementalSearchKeyboardHandler, HashHandler);
  165. (function() {
  166. this.attach = function(editor) {
  167. var iSearch = this.$iSearch;
  168. HashHandler.call(this, exports.iSearchCommands, editor.commands.platform);
  169. this.$commandExecHandler = editor.commands.addEventListener('exec', function(e) {
  170. if (!e.command.isIncrementalSearchCommand)
  171. return iSearch.deactivate();
  172. e.stopPropagation();
  173. e.preventDefault();
  174. var scrollTop = editor.session.getScrollTop();
  175. var result = e.command.exec(iSearch, e.args || {});
  176. editor.renderer.scrollCursorIntoView(null, 0.5);
  177. editor.renderer.animateScrolling(scrollTop);
  178. return result;
  179. });
  180. };
  181. this.detach = function(editor) {
  182. if (!this.$commandExecHandler) return;
  183. editor.commands.removeEventListener('exec', this.$commandExecHandler);
  184. delete this.$commandExecHandler;
  185. };
  186. var handleKeyboard$super = this.handleKeyboard;
  187. this.handleKeyboard = function(data, hashId, key, keyCode) {
  188. if (((hashId === 1/*ctrl*/ || hashId === 8/*command*/) && key === 'v')
  189. || (hashId === 1/*ctrl*/ && key === 'y')) return null;
  190. var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode);
  191. if (cmd.command) { return cmd; }
  192. if (hashId == -1) {
  193. var extendCmd = this.commands.extendSearchTerm;
  194. if (extendCmd) { return {command: extendCmd, args: key}; }
  195. }
  196. return false;
  197. };
  198. }).call(IncrementalSearchKeyboardHandler.prototype);
  199. exports.IncrementalSearchKeyboardHandler = IncrementalSearchKeyboardHandler;
  200. });