5aeca18ddade13f4ae431739cc44e9a5957c9fa4487535cfcb39a72725880a4078564b27b6b44471ab63e8876d568a5fdbfbd084d25e73e4b56617a082189b 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  6. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  7. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  8. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  9. return c > 3 && r && Object.defineProperty(target, key, r), r;
  10. };
  11. var __param = (this && this.__param) || function (paramIndex, decorator) {
  12. return function (target, key) { decorator(target, key, paramIndex); }
  13. };
  14. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  15. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  16. return new (P || (P = Promise))(function (resolve, reject) {
  17. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  18. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  19. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  20. step((generator = generator.apply(thisArg, _arguments || [])).next());
  21. });
  22. };
  23. import { Delayer } from '../../../../base/common/async.js';
  24. import { Disposable } from '../../../../base/common/lifecycle.js';
  25. import * as strings from '../../../../base/common/strings.js';
  26. import { EditorAction, EditorCommand, MultiEditorAction, registerEditorAction, registerEditorCommand, registerEditorContribution, registerMultiEditorAction } from '../../../browser/editorExtensions.js';
  27. import { EditorContextKeys } from '../../../common/editorContextKeys.js';
  28. import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_FIND_WIDGET_VISIBLE, CONTEXT_REPLACE_INPUT_FOCUSED, FindModelBoundToEditorModel, FIND_IDS, ToggleCaseSensitiveKeybinding, TogglePreserveCaseKeybinding, ToggleRegexKeybinding, ToggleSearchScopeKeybinding, ToggleWholeWordKeybinding } from './findModel.js';
  29. import { FindOptionsWidget } from './findOptionsWidget.js';
  30. import { FindReplaceState } from './findState.js';
  31. import { FindWidget } from './findWidget.js';
  32. import * as nls from '../../../../nls.js';
  33. import { MenuId } from '../../../../platform/actions/common/actions.js';
  34. import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';
  35. import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
  36. import { IContextViewService } from '../../../../platform/contextview/browser/contextView.js';
  37. import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';
  38. import { INotificationService } from '../../../../platform/notification/common/notification.js';
  39. import { IStorageService } from '../../../../platform/storage/common/storage.js';
  40. import { IThemeService } from '../../../../platform/theme/common/themeService.js';
  41. const SEARCH_STRING_MAX_LENGTH = 524288;
  42. export function getSelectionSearchString(editor, seedSearchStringFromSelection = 'single', seedSearchStringFromNonEmptySelection = false) {
  43. if (!editor.hasModel()) {
  44. return null;
  45. }
  46. const selection = editor.getSelection();
  47. // if selection spans multiple lines, default search string to empty
  48. if ((seedSearchStringFromSelection === 'single' && selection.startLineNumber === selection.endLineNumber)
  49. || seedSearchStringFromSelection === 'multiple') {
  50. if (selection.isEmpty()) {
  51. const wordAtPosition = editor.getConfiguredWordAtPosition(selection.getStartPosition());
  52. if (wordAtPosition && (false === seedSearchStringFromNonEmptySelection)) {
  53. return wordAtPosition.word;
  54. }
  55. }
  56. else {
  57. if (editor.getModel().getValueLengthInRange(selection) < SEARCH_STRING_MAX_LENGTH) {
  58. return editor.getModel().getValueInRange(selection);
  59. }
  60. }
  61. }
  62. return null;
  63. }
  64. let CommonFindController = class CommonFindController extends Disposable {
  65. constructor(editor, contextKeyService, storageService, clipboardService) {
  66. super();
  67. this._editor = editor;
  68. this._findWidgetVisible = CONTEXT_FIND_WIDGET_VISIBLE.bindTo(contextKeyService);
  69. this._contextKeyService = contextKeyService;
  70. this._storageService = storageService;
  71. this._clipboardService = clipboardService;
  72. this._updateHistoryDelayer = new Delayer(500);
  73. this._state = this._register(new FindReplaceState());
  74. this.loadQueryState();
  75. this._register(this._state.onFindReplaceStateChange((e) => this._onStateChanged(e)));
  76. this._model = null;
  77. this._register(this._editor.onDidChangeModel(() => {
  78. const shouldRestartFind = (this._editor.getModel() && this._state.isRevealed);
  79. this.disposeModel();
  80. this._state.change({
  81. searchScope: null,
  82. matchCase: this._storageService.getBoolean('editor.matchCase', 1 /* StorageScope.WORKSPACE */, false),
  83. wholeWord: this._storageService.getBoolean('editor.wholeWord', 1 /* StorageScope.WORKSPACE */, false),
  84. isRegex: this._storageService.getBoolean('editor.isRegex', 1 /* StorageScope.WORKSPACE */, false),
  85. preserveCase: this._storageService.getBoolean('editor.preserveCase', 1 /* StorageScope.WORKSPACE */, false)
  86. }, false);
  87. if (shouldRestartFind) {
  88. this._start({
  89. forceRevealReplace: false,
  90. seedSearchStringFromSelection: 'none',
  91. seedSearchStringFromNonEmptySelection: false,
  92. seedSearchStringFromGlobalClipboard: false,
  93. shouldFocus: 0 /* FindStartFocusAction.NoFocusChange */,
  94. shouldAnimate: false,
  95. updateSearchScope: false,
  96. loop: this._editor.getOption(37 /* EditorOption.find */).loop
  97. });
  98. }
  99. }));
  100. }
  101. get editor() {
  102. return this._editor;
  103. }
  104. static get(editor) {
  105. return editor.getContribution(CommonFindController.ID);
  106. }
  107. dispose() {
  108. this.disposeModel();
  109. super.dispose();
  110. }
  111. disposeModel() {
  112. if (this._model) {
  113. this._model.dispose();
  114. this._model = null;
  115. }
  116. }
  117. _onStateChanged(e) {
  118. this.saveQueryState(e);
  119. if (e.isRevealed) {
  120. if (this._state.isRevealed) {
  121. this._findWidgetVisible.set(true);
  122. }
  123. else {
  124. this._findWidgetVisible.reset();
  125. this.disposeModel();
  126. }
  127. }
  128. if (e.searchString) {
  129. this.setGlobalBufferTerm(this._state.searchString);
  130. }
  131. }
  132. saveQueryState(e) {
  133. if (e.isRegex) {
  134. this._storageService.store('editor.isRegex', this._state.actualIsRegex, 1 /* StorageScope.WORKSPACE */, 0 /* StorageTarget.USER */);
  135. }
  136. if (e.wholeWord) {
  137. this._storageService.store('editor.wholeWord', this._state.actualWholeWord, 1 /* StorageScope.WORKSPACE */, 0 /* StorageTarget.USER */);
  138. }
  139. if (e.matchCase) {
  140. this._storageService.store('editor.matchCase', this._state.actualMatchCase, 1 /* StorageScope.WORKSPACE */, 0 /* StorageTarget.USER */);
  141. }
  142. if (e.preserveCase) {
  143. this._storageService.store('editor.preserveCase', this._state.actualPreserveCase, 1 /* StorageScope.WORKSPACE */, 0 /* StorageTarget.USER */);
  144. }
  145. }
  146. loadQueryState() {
  147. this._state.change({
  148. matchCase: this._storageService.getBoolean('editor.matchCase', 1 /* StorageScope.WORKSPACE */, this._state.matchCase),
  149. wholeWord: this._storageService.getBoolean('editor.wholeWord', 1 /* StorageScope.WORKSPACE */, this._state.wholeWord),
  150. isRegex: this._storageService.getBoolean('editor.isRegex', 1 /* StorageScope.WORKSPACE */, this._state.isRegex),
  151. preserveCase: this._storageService.getBoolean('editor.preserveCase', 1 /* StorageScope.WORKSPACE */, this._state.preserveCase)
  152. }, false);
  153. }
  154. isFindInputFocused() {
  155. return !!CONTEXT_FIND_INPUT_FOCUSED.getValue(this._contextKeyService);
  156. }
  157. getState() {
  158. return this._state;
  159. }
  160. closeFindWidget() {
  161. this._state.change({
  162. isRevealed: false,
  163. searchScope: null
  164. }, false);
  165. this._editor.focus();
  166. }
  167. toggleCaseSensitive() {
  168. this._state.change({ matchCase: !this._state.matchCase }, false);
  169. if (!this._state.isRevealed) {
  170. this.highlightFindOptions();
  171. }
  172. }
  173. toggleWholeWords() {
  174. this._state.change({ wholeWord: !this._state.wholeWord }, false);
  175. if (!this._state.isRevealed) {
  176. this.highlightFindOptions();
  177. }
  178. }
  179. toggleRegex() {
  180. this._state.change({ isRegex: !this._state.isRegex }, false);
  181. if (!this._state.isRevealed) {
  182. this.highlightFindOptions();
  183. }
  184. }
  185. togglePreserveCase() {
  186. this._state.change({ preserveCase: !this._state.preserveCase }, false);
  187. if (!this._state.isRevealed) {
  188. this.highlightFindOptions();
  189. }
  190. }
  191. toggleSearchScope() {
  192. if (this._state.searchScope) {
  193. this._state.change({ searchScope: null }, true);
  194. }
  195. else {
  196. if (this._editor.hasModel()) {
  197. const selections = this._editor.getSelections();
  198. selections.map(selection => {
  199. if (selection.endColumn === 1 && selection.endLineNumber > selection.startLineNumber) {
  200. selection = selection.setEndPosition(selection.endLineNumber - 1, this._editor.getModel().getLineMaxColumn(selection.endLineNumber - 1));
  201. }
  202. if (!selection.isEmpty()) {
  203. return selection;
  204. }
  205. return null;
  206. }).filter(element => !!element);
  207. if (selections.length) {
  208. this._state.change({ searchScope: selections }, true);
  209. }
  210. }
  211. }
  212. }
  213. setSearchString(searchString) {
  214. if (this._state.isRegex) {
  215. searchString = strings.escapeRegExpCharacters(searchString);
  216. }
  217. this._state.change({ searchString: searchString }, false);
  218. }
  219. highlightFindOptions(ignoreWhenVisible = false) {
  220. // overwritten in subclass
  221. }
  222. _start(opts, newState) {
  223. return __awaiter(this, void 0, void 0, function* () {
  224. this.disposeModel();
  225. if (!this._editor.hasModel()) {
  226. // cannot do anything with an editor that doesn't have a model...
  227. return;
  228. }
  229. const stateChanges = Object.assign(Object.assign({}, newState), { isRevealed: true });
  230. if (opts.seedSearchStringFromSelection === 'single') {
  231. const selectionSearchString = getSelectionSearchString(this._editor, opts.seedSearchStringFromSelection, opts.seedSearchStringFromNonEmptySelection);
  232. if (selectionSearchString) {
  233. if (this._state.isRegex) {
  234. stateChanges.searchString = strings.escapeRegExpCharacters(selectionSearchString);
  235. }
  236. else {
  237. stateChanges.searchString = selectionSearchString;
  238. }
  239. }
  240. }
  241. else if (opts.seedSearchStringFromSelection === 'multiple' && !opts.updateSearchScope) {
  242. const selectionSearchString = getSelectionSearchString(this._editor, opts.seedSearchStringFromSelection);
  243. if (selectionSearchString) {
  244. stateChanges.searchString = selectionSearchString;
  245. }
  246. }
  247. if (!stateChanges.searchString && opts.seedSearchStringFromGlobalClipboard) {
  248. const selectionSearchString = yield this.getGlobalBufferTerm();
  249. if (!this._editor.hasModel()) {
  250. // the editor has lost its model in the meantime
  251. return;
  252. }
  253. if (selectionSearchString) {
  254. stateChanges.searchString = selectionSearchString;
  255. }
  256. }
  257. // Overwrite isReplaceRevealed
  258. if (opts.forceRevealReplace || stateChanges.isReplaceRevealed) {
  259. stateChanges.isReplaceRevealed = true;
  260. }
  261. else if (!this._findWidgetVisible.get()) {
  262. stateChanges.isReplaceRevealed = false;
  263. }
  264. if (opts.updateSearchScope) {
  265. const currentSelections = this._editor.getSelections();
  266. if (currentSelections.some(selection => !selection.isEmpty())) {
  267. stateChanges.searchScope = currentSelections;
  268. }
  269. }
  270. stateChanges.loop = opts.loop;
  271. this._state.change(stateChanges, false);
  272. if (!this._model) {
  273. this._model = new FindModelBoundToEditorModel(this._editor, this._state);
  274. }
  275. });
  276. }
  277. start(opts, newState) {
  278. return this._start(opts, newState);
  279. }
  280. moveToNextMatch() {
  281. if (this._model) {
  282. this._model.moveToNextMatch();
  283. return true;
  284. }
  285. return false;
  286. }
  287. moveToPrevMatch() {
  288. if (this._model) {
  289. this._model.moveToPrevMatch();
  290. return true;
  291. }
  292. return false;
  293. }
  294. replace() {
  295. if (this._model) {
  296. this._model.replace();
  297. return true;
  298. }
  299. return false;
  300. }
  301. replaceAll() {
  302. if (this._model) {
  303. this._model.replaceAll();
  304. return true;
  305. }
  306. return false;
  307. }
  308. selectAllMatches() {
  309. if (this._model) {
  310. this._model.selectAllMatches();
  311. this._editor.focus();
  312. return true;
  313. }
  314. return false;
  315. }
  316. getGlobalBufferTerm() {
  317. return __awaiter(this, void 0, void 0, function* () {
  318. if (this._editor.getOption(37 /* EditorOption.find */).globalFindClipboard
  319. && this._editor.hasModel()
  320. && !this._editor.getModel().isTooLargeForSyncing()) {
  321. return this._clipboardService.readFindText();
  322. }
  323. return '';
  324. });
  325. }
  326. setGlobalBufferTerm(text) {
  327. if (this._editor.getOption(37 /* EditorOption.find */).globalFindClipboard
  328. && this._editor.hasModel()
  329. && !this._editor.getModel().isTooLargeForSyncing()) {
  330. // intentionally not awaited
  331. this._clipboardService.writeFindText(text);
  332. }
  333. }
  334. };
  335. CommonFindController.ID = 'editor.contrib.findController';
  336. CommonFindController = __decorate([
  337. __param(1, IContextKeyService),
  338. __param(2, IStorageService),
  339. __param(3, IClipboardService)
  340. ], CommonFindController);
  341. export { CommonFindController };
  342. let FindController = class FindController extends CommonFindController {
  343. constructor(editor, _contextViewService, _contextKeyService, _keybindingService, _themeService, _notificationService, _storageService, clipboardService) {
  344. super(editor, _contextKeyService, _storageService, clipboardService);
  345. this._contextViewService = _contextViewService;
  346. this._keybindingService = _keybindingService;
  347. this._themeService = _themeService;
  348. this._notificationService = _notificationService;
  349. this._widget = null;
  350. this._findOptionsWidget = null;
  351. }
  352. _start(opts, newState) {
  353. const _super = Object.create(null, {
  354. _start: { get: () => super._start }
  355. });
  356. return __awaiter(this, void 0, void 0, function* () {
  357. if (!this._widget) {
  358. this._createFindWidget();
  359. }
  360. const selection = this._editor.getSelection();
  361. let updateSearchScope = false;
  362. switch (this._editor.getOption(37 /* EditorOption.find */).autoFindInSelection) {
  363. case 'always':
  364. updateSearchScope = true;
  365. break;
  366. case 'never':
  367. updateSearchScope = false;
  368. break;
  369. case 'multiline': {
  370. const isSelectionMultipleLine = !!selection && selection.startLineNumber !== selection.endLineNumber;
  371. updateSearchScope = isSelectionMultipleLine;
  372. break;
  373. }
  374. default:
  375. break;
  376. }
  377. opts.updateSearchScope = opts.updateSearchScope || updateSearchScope;
  378. yield _super._start.call(this, opts, newState);
  379. if (this._widget) {
  380. if (opts.shouldFocus === 2 /* FindStartFocusAction.FocusReplaceInput */) {
  381. this._widget.focusReplaceInput();
  382. }
  383. else if (opts.shouldFocus === 1 /* FindStartFocusAction.FocusFindInput */) {
  384. this._widget.focusFindInput();
  385. }
  386. }
  387. });
  388. }
  389. highlightFindOptions(ignoreWhenVisible = false) {
  390. if (!this._widget) {
  391. this._createFindWidget();
  392. }
  393. if (this._state.isRevealed && !ignoreWhenVisible) {
  394. this._widget.highlightFindOptions();
  395. }
  396. else {
  397. this._findOptionsWidget.highlightFindOptions();
  398. }
  399. }
  400. _createFindWidget() {
  401. this._widget = this._register(new FindWidget(this._editor, this, this._state, this._contextViewService, this._keybindingService, this._contextKeyService, this._themeService, this._storageService, this._notificationService));
  402. this._findOptionsWidget = this._register(new FindOptionsWidget(this._editor, this._state, this._keybindingService, this._themeService));
  403. }
  404. };
  405. FindController = __decorate([
  406. __param(1, IContextViewService),
  407. __param(2, IContextKeyService),
  408. __param(3, IKeybindingService),
  409. __param(4, IThemeService),
  410. __param(5, INotificationService),
  411. __param(6, IStorageService),
  412. __param(7, IClipboardService)
  413. ], FindController);
  414. export { FindController };
  415. export const StartFindAction = registerMultiEditorAction(new MultiEditorAction({
  416. id: FIND_IDS.StartFindAction,
  417. label: nls.localize('startFindAction', "Find"),
  418. alias: 'Find',
  419. precondition: ContextKeyExpr.or(EditorContextKeys.focus, ContextKeyExpr.has('editorIsOpen')),
  420. kbOpts: {
  421. kbExpr: null,
  422. primary: 2048 /* KeyMod.CtrlCmd */ | 36 /* KeyCode.KeyF */,
  423. weight: 100 /* KeybindingWeight.EditorContrib */
  424. },
  425. menuOpts: {
  426. menuId: MenuId.MenubarEditMenu,
  427. group: '3_find',
  428. title: nls.localize({ key: 'miFind', comment: ['&& denotes a mnemonic'] }, "&&Find"),
  429. order: 1
  430. }
  431. }));
  432. StartFindAction.addImplementation(0, (accessor, editor, args) => {
  433. const controller = CommonFindController.get(editor);
  434. if (!controller) {
  435. return false;
  436. }
  437. return controller.start({
  438. forceRevealReplace: false,
  439. seedSearchStringFromSelection: editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection !== 'never' ? 'single' : 'none',
  440. seedSearchStringFromNonEmptySelection: editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection === 'selection',
  441. seedSearchStringFromGlobalClipboard: editor.getOption(37 /* EditorOption.find */).globalFindClipboard,
  442. shouldFocus: 1 /* FindStartFocusAction.FocusFindInput */,
  443. shouldAnimate: true,
  444. updateSearchScope: false,
  445. loop: editor.getOption(37 /* EditorOption.find */).loop
  446. });
  447. });
  448. const findArgDescription = {
  449. description: 'Open a new In-Editor Find Widget.',
  450. args: [{
  451. name: 'Open a new In-Editor Find Widget args',
  452. schema: {
  453. properties: {
  454. searchString: { type: 'string' },
  455. replaceString: { type: 'string' },
  456. regex: { type: 'boolean' },
  457. regexOverride: {
  458. type: 'number',
  459. description: nls.localize('actions.find.isRegexOverride', 'Overrides "Use Regular Expression" flag.\nThe flag will not be saved for the future.\n0: Do Nothing\n1: True\n2: False')
  460. },
  461. wholeWord: { type: 'boolean' },
  462. wholeWordOverride: {
  463. type: 'number',
  464. description: nls.localize('actions.find.wholeWordOverride', 'Overrides "Match Whole Word" flag.\nThe flag will not be saved for the future.\n0: Do Nothing\n1: True\n2: False')
  465. },
  466. matchCase: { type: 'boolean' },
  467. matchCaseOverride: {
  468. type: 'number',
  469. description: nls.localize('actions.find.matchCaseOverride', 'Overrides "Math Case" flag.\nThe flag will not be saved for the future.\n0: Do Nothing\n1: True\n2: False')
  470. },
  471. preserveCase: { type: 'boolean' },
  472. preserveCaseOverride: {
  473. type: 'number',
  474. description: nls.localize('actions.find.preserveCaseOverride', 'Overrides "Preserve Case" flag.\nThe flag will not be saved for the future.\n0: Do Nothing\n1: True\n2: False')
  475. },
  476. findInSelection: { type: 'boolean' },
  477. }
  478. }
  479. }]
  480. };
  481. export class StartFindWithArgsAction extends EditorAction {
  482. constructor() {
  483. super({
  484. id: FIND_IDS.StartFindWithArgs,
  485. label: nls.localize('startFindWithArgsAction', "Find With Arguments"),
  486. alias: 'Find With Arguments',
  487. precondition: undefined,
  488. kbOpts: {
  489. kbExpr: null,
  490. primary: 0,
  491. weight: 100 /* KeybindingWeight.EditorContrib */
  492. },
  493. description: findArgDescription
  494. });
  495. }
  496. run(accessor, editor, args) {
  497. return __awaiter(this, void 0, void 0, function* () {
  498. const controller = CommonFindController.get(editor);
  499. if (controller) {
  500. const newState = args ? {
  501. searchString: args.searchString,
  502. replaceString: args.replaceString,
  503. isReplaceRevealed: args.replaceString !== undefined,
  504. isRegex: args.isRegex,
  505. // isRegexOverride: args.regexOverride,
  506. wholeWord: args.matchWholeWord,
  507. // wholeWordOverride: args.wholeWordOverride,
  508. matchCase: args.isCaseSensitive,
  509. // matchCaseOverride: args.matchCaseOverride,
  510. preserveCase: args.preserveCase,
  511. // preserveCaseOverride: args.preserveCaseOverride,
  512. } : {};
  513. yield controller.start({
  514. forceRevealReplace: false,
  515. seedSearchStringFromSelection: (controller.getState().searchString.length === 0) && editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection !== 'never' ? 'single' : 'none',
  516. seedSearchStringFromNonEmptySelection: editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection === 'selection',
  517. seedSearchStringFromGlobalClipboard: true,
  518. shouldFocus: 1 /* FindStartFocusAction.FocusFindInput */,
  519. shouldAnimate: true,
  520. updateSearchScope: (args === null || args === void 0 ? void 0 : args.findInSelection) || false,
  521. loop: editor.getOption(37 /* EditorOption.find */).loop
  522. }, newState);
  523. controller.setGlobalBufferTerm(controller.getState().searchString);
  524. }
  525. });
  526. }
  527. }
  528. export class StartFindWithSelectionAction extends EditorAction {
  529. constructor() {
  530. super({
  531. id: FIND_IDS.StartFindWithSelection,
  532. label: nls.localize('startFindWithSelectionAction', "Find With Selection"),
  533. alias: 'Find With Selection',
  534. precondition: undefined,
  535. kbOpts: {
  536. kbExpr: null,
  537. primary: 0,
  538. mac: {
  539. primary: 2048 /* KeyMod.CtrlCmd */ | 35 /* KeyCode.KeyE */,
  540. },
  541. weight: 100 /* KeybindingWeight.EditorContrib */
  542. }
  543. });
  544. }
  545. run(accessor, editor) {
  546. return __awaiter(this, void 0, void 0, function* () {
  547. const controller = CommonFindController.get(editor);
  548. if (controller) {
  549. yield controller.start({
  550. forceRevealReplace: false,
  551. seedSearchStringFromSelection: 'multiple',
  552. seedSearchStringFromNonEmptySelection: false,
  553. seedSearchStringFromGlobalClipboard: false,
  554. shouldFocus: 0 /* FindStartFocusAction.NoFocusChange */,
  555. shouldAnimate: true,
  556. updateSearchScope: false,
  557. loop: editor.getOption(37 /* EditorOption.find */).loop
  558. });
  559. controller.setGlobalBufferTerm(controller.getState().searchString);
  560. }
  561. });
  562. }
  563. }
  564. export class MatchFindAction extends EditorAction {
  565. run(accessor, editor) {
  566. return __awaiter(this, void 0, void 0, function* () {
  567. const controller = CommonFindController.get(editor);
  568. if (controller && !this._run(controller)) {
  569. yield controller.start({
  570. forceRevealReplace: false,
  571. seedSearchStringFromSelection: (controller.getState().searchString.length === 0) && editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection !== 'never' ? 'single' : 'none',
  572. seedSearchStringFromNonEmptySelection: editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection === 'selection',
  573. seedSearchStringFromGlobalClipboard: true,
  574. shouldFocus: 0 /* FindStartFocusAction.NoFocusChange */,
  575. shouldAnimate: true,
  576. updateSearchScope: false,
  577. loop: editor.getOption(37 /* EditorOption.find */).loop
  578. });
  579. this._run(controller);
  580. }
  581. });
  582. }
  583. }
  584. export class NextMatchFindAction extends MatchFindAction {
  585. constructor() {
  586. super({
  587. id: FIND_IDS.NextMatchFindAction,
  588. label: nls.localize('findNextMatchAction', "Find Next"),
  589. alias: 'Find Next',
  590. precondition: undefined,
  591. kbOpts: [{
  592. kbExpr: EditorContextKeys.focus,
  593. primary: 61 /* KeyCode.F3 */,
  594. mac: { primary: 2048 /* KeyMod.CtrlCmd */ | 37 /* KeyCode.KeyG */, secondary: [61 /* KeyCode.F3 */] },
  595. weight: 100 /* KeybindingWeight.EditorContrib */
  596. }, {
  597. kbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_FIND_INPUT_FOCUSED),
  598. primary: 3 /* KeyCode.Enter */,
  599. weight: 100 /* KeybindingWeight.EditorContrib */
  600. }]
  601. });
  602. }
  603. _run(controller) {
  604. const result = controller.moveToNextMatch();
  605. if (result) {
  606. controller.editor.pushUndoStop();
  607. return true;
  608. }
  609. return false;
  610. }
  611. }
  612. export class PreviousMatchFindAction extends MatchFindAction {
  613. constructor() {
  614. super({
  615. id: FIND_IDS.PreviousMatchFindAction,
  616. label: nls.localize('findPreviousMatchAction', "Find Previous"),
  617. alias: 'Find Previous',
  618. precondition: undefined,
  619. kbOpts: [{
  620. kbExpr: EditorContextKeys.focus,
  621. primary: 1024 /* KeyMod.Shift */ | 61 /* KeyCode.F3 */,
  622. mac: { primary: 2048 /* KeyMod.CtrlCmd */ | 1024 /* KeyMod.Shift */ | 37 /* KeyCode.KeyG */, secondary: [1024 /* KeyMod.Shift */ | 61 /* KeyCode.F3 */] },
  623. weight: 100 /* KeybindingWeight.EditorContrib */
  624. }, {
  625. kbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_FIND_INPUT_FOCUSED),
  626. primary: 1024 /* KeyMod.Shift */ | 3 /* KeyCode.Enter */,
  627. weight: 100 /* KeybindingWeight.EditorContrib */
  628. }
  629. ]
  630. });
  631. }
  632. _run(controller) {
  633. return controller.moveToPrevMatch();
  634. }
  635. }
  636. export class SelectionMatchFindAction extends EditorAction {
  637. run(accessor, editor) {
  638. return __awaiter(this, void 0, void 0, function* () {
  639. const controller = CommonFindController.get(editor);
  640. if (!controller) {
  641. return;
  642. }
  643. const seedSearchStringFromNonEmptySelection = editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection === 'selection';
  644. let selectionSearchString = null;
  645. if (editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection !== 'never') {
  646. selectionSearchString = getSelectionSearchString(editor, 'single', seedSearchStringFromNonEmptySelection);
  647. }
  648. if (selectionSearchString) {
  649. controller.setSearchString(selectionSearchString);
  650. }
  651. if (!this._run(controller)) {
  652. yield controller.start({
  653. forceRevealReplace: false,
  654. seedSearchStringFromSelection: editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection !== 'never' ? 'single' : 'none',
  655. seedSearchStringFromNonEmptySelection: seedSearchStringFromNonEmptySelection,
  656. seedSearchStringFromGlobalClipboard: false,
  657. shouldFocus: 0 /* FindStartFocusAction.NoFocusChange */,
  658. shouldAnimate: true,
  659. updateSearchScope: false,
  660. loop: editor.getOption(37 /* EditorOption.find */).loop
  661. });
  662. this._run(controller);
  663. }
  664. });
  665. }
  666. }
  667. export class NextSelectionMatchFindAction extends SelectionMatchFindAction {
  668. constructor() {
  669. super({
  670. id: FIND_IDS.NextSelectionMatchFindAction,
  671. label: nls.localize('nextSelectionMatchFindAction', "Find Next Selection"),
  672. alias: 'Find Next Selection',
  673. precondition: undefined,
  674. kbOpts: {
  675. kbExpr: EditorContextKeys.focus,
  676. primary: 2048 /* KeyMod.CtrlCmd */ | 61 /* KeyCode.F3 */,
  677. weight: 100 /* KeybindingWeight.EditorContrib */
  678. }
  679. });
  680. }
  681. _run(controller) {
  682. return controller.moveToNextMatch();
  683. }
  684. }
  685. export class PreviousSelectionMatchFindAction extends SelectionMatchFindAction {
  686. constructor() {
  687. super({
  688. id: FIND_IDS.PreviousSelectionMatchFindAction,
  689. label: nls.localize('previousSelectionMatchFindAction', "Find Previous Selection"),
  690. alias: 'Find Previous Selection',
  691. precondition: undefined,
  692. kbOpts: {
  693. kbExpr: EditorContextKeys.focus,
  694. primary: 2048 /* KeyMod.CtrlCmd */ | 1024 /* KeyMod.Shift */ | 61 /* KeyCode.F3 */,
  695. weight: 100 /* KeybindingWeight.EditorContrib */
  696. }
  697. });
  698. }
  699. _run(controller) {
  700. return controller.moveToPrevMatch();
  701. }
  702. }
  703. export const StartFindReplaceAction = registerMultiEditorAction(new MultiEditorAction({
  704. id: FIND_IDS.StartFindReplaceAction,
  705. label: nls.localize('startReplace', "Replace"),
  706. alias: 'Replace',
  707. precondition: ContextKeyExpr.or(EditorContextKeys.focus, ContextKeyExpr.has('editorIsOpen')),
  708. kbOpts: {
  709. kbExpr: null,
  710. primary: 2048 /* KeyMod.CtrlCmd */ | 38 /* KeyCode.KeyH */,
  711. mac: { primary: 2048 /* KeyMod.CtrlCmd */ | 512 /* KeyMod.Alt */ | 36 /* KeyCode.KeyF */ },
  712. weight: 100 /* KeybindingWeight.EditorContrib */
  713. },
  714. menuOpts: {
  715. menuId: MenuId.MenubarEditMenu,
  716. group: '3_find',
  717. title: nls.localize({ key: 'miReplace', comment: ['&& denotes a mnemonic'] }, "&&Replace"),
  718. order: 2
  719. }
  720. }));
  721. StartFindReplaceAction.addImplementation(0, (accessor, editor, args) => {
  722. if (!editor.hasModel() || editor.getOption(83 /* EditorOption.readOnly */)) {
  723. return false;
  724. }
  725. const controller = CommonFindController.get(editor);
  726. if (!controller) {
  727. return false;
  728. }
  729. const currentSelection = editor.getSelection();
  730. const findInputFocused = controller.isFindInputFocused();
  731. // we only seed search string from selection when the current selection is single line and not empty,
  732. // + the find input is not focused
  733. const seedSearchStringFromSelection = !currentSelection.isEmpty()
  734. && currentSelection.startLineNumber === currentSelection.endLineNumber
  735. && (editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection !== 'never')
  736. && !findInputFocused;
  737. /*
  738. * if the existing search string in find widget is empty and we don't seed search string from selection, it means the Find Input is still empty, so we should focus the Find Input instead of Replace Input.
  739. * findInputFocused true -> seedSearchStringFromSelection false, FocusReplaceInput
  740. * findInputFocused false, seedSearchStringFromSelection true FocusReplaceInput
  741. * findInputFocused false seedSearchStringFromSelection false FocusFindInput
  742. */
  743. const shouldFocus = (findInputFocused || seedSearchStringFromSelection) ?
  744. 2 /* FindStartFocusAction.FocusReplaceInput */ : 1 /* FindStartFocusAction.FocusFindInput */;
  745. return controller.start({
  746. forceRevealReplace: true,
  747. seedSearchStringFromSelection: seedSearchStringFromSelection ? 'single' : 'none',
  748. seedSearchStringFromNonEmptySelection: editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection === 'selection',
  749. seedSearchStringFromGlobalClipboard: editor.getOption(37 /* EditorOption.find */).seedSearchStringFromSelection !== 'never',
  750. shouldFocus: shouldFocus,
  751. shouldAnimate: true,
  752. updateSearchScope: false,
  753. loop: editor.getOption(37 /* EditorOption.find */).loop
  754. });
  755. });
  756. registerEditorContribution(CommonFindController.ID, FindController);
  757. registerEditorAction(StartFindWithArgsAction);
  758. registerEditorAction(StartFindWithSelectionAction);
  759. registerEditorAction(NextMatchFindAction);
  760. registerEditorAction(PreviousMatchFindAction);
  761. registerEditorAction(NextSelectionMatchFindAction);
  762. registerEditorAction(PreviousSelectionMatchFindAction);
  763. const FindCommand = EditorCommand.bindToContribution(CommonFindController.get);
  764. registerEditorCommand(new FindCommand({
  765. id: FIND_IDS.CloseFindWidgetCommand,
  766. precondition: CONTEXT_FIND_WIDGET_VISIBLE,
  767. handler: x => x.closeFindWidget(),
  768. kbOpts: {
  769. weight: 100 /* KeybindingWeight.EditorContrib */ + 5,
  770. kbExpr: ContextKeyExpr.and(EditorContextKeys.focus, ContextKeyExpr.not('isComposing')),
  771. primary: 9 /* KeyCode.Escape */,
  772. secondary: [1024 /* KeyMod.Shift */ | 9 /* KeyCode.Escape */]
  773. }
  774. }));
  775. registerEditorCommand(new FindCommand({
  776. id: FIND_IDS.ToggleCaseSensitiveCommand,
  777. precondition: undefined,
  778. handler: x => x.toggleCaseSensitive(),
  779. kbOpts: {
  780. weight: 100 /* KeybindingWeight.EditorContrib */ + 5,
  781. kbExpr: EditorContextKeys.focus,
  782. primary: ToggleCaseSensitiveKeybinding.primary,
  783. mac: ToggleCaseSensitiveKeybinding.mac,
  784. win: ToggleCaseSensitiveKeybinding.win,
  785. linux: ToggleCaseSensitiveKeybinding.linux
  786. }
  787. }));
  788. registerEditorCommand(new FindCommand({
  789. id: FIND_IDS.ToggleWholeWordCommand,
  790. precondition: undefined,
  791. handler: x => x.toggleWholeWords(),
  792. kbOpts: {
  793. weight: 100 /* KeybindingWeight.EditorContrib */ + 5,
  794. kbExpr: EditorContextKeys.focus,
  795. primary: ToggleWholeWordKeybinding.primary,
  796. mac: ToggleWholeWordKeybinding.mac,
  797. win: ToggleWholeWordKeybinding.win,
  798. linux: ToggleWholeWordKeybinding.linux
  799. }
  800. }));
  801. registerEditorCommand(new FindCommand({
  802. id: FIND_IDS.ToggleRegexCommand,
  803. precondition: undefined,
  804. handler: x => x.toggleRegex(),
  805. kbOpts: {
  806. weight: 100 /* KeybindingWeight.EditorContrib */ + 5,
  807. kbExpr: EditorContextKeys.focus,
  808. primary: ToggleRegexKeybinding.primary,
  809. mac: ToggleRegexKeybinding.mac,
  810. win: ToggleRegexKeybinding.win,
  811. linux: ToggleRegexKeybinding.linux
  812. }
  813. }));
  814. registerEditorCommand(new FindCommand({
  815. id: FIND_IDS.ToggleSearchScopeCommand,
  816. precondition: undefined,
  817. handler: x => x.toggleSearchScope(),
  818. kbOpts: {
  819. weight: 100 /* KeybindingWeight.EditorContrib */ + 5,
  820. kbExpr: EditorContextKeys.focus,
  821. primary: ToggleSearchScopeKeybinding.primary,
  822. mac: ToggleSearchScopeKeybinding.mac,
  823. win: ToggleSearchScopeKeybinding.win,
  824. linux: ToggleSearchScopeKeybinding.linux
  825. }
  826. }));
  827. registerEditorCommand(new FindCommand({
  828. id: FIND_IDS.TogglePreserveCaseCommand,
  829. precondition: undefined,
  830. handler: x => x.togglePreserveCase(),
  831. kbOpts: {
  832. weight: 100 /* KeybindingWeight.EditorContrib */ + 5,
  833. kbExpr: EditorContextKeys.focus,
  834. primary: TogglePreserveCaseKeybinding.primary,
  835. mac: TogglePreserveCaseKeybinding.mac,
  836. win: TogglePreserveCaseKeybinding.win,
  837. linux: TogglePreserveCaseKeybinding.linux
  838. }
  839. }));
  840. registerEditorCommand(new FindCommand({
  841. id: FIND_IDS.ReplaceOneAction,
  842. precondition: CONTEXT_FIND_WIDGET_VISIBLE,
  843. handler: x => x.replace(),
  844. kbOpts: {
  845. weight: 100 /* KeybindingWeight.EditorContrib */ + 5,
  846. kbExpr: EditorContextKeys.focus,
  847. primary: 2048 /* KeyMod.CtrlCmd */ | 1024 /* KeyMod.Shift */ | 22 /* KeyCode.Digit1 */
  848. }
  849. }));
  850. registerEditorCommand(new FindCommand({
  851. id: FIND_IDS.ReplaceOneAction,
  852. precondition: CONTEXT_FIND_WIDGET_VISIBLE,
  853. handler: x => x.replace(),
  854. kbOpts: {
  855. weight: 100 /* KeybindingWeight.EditorContrib */ + 5,
  856. kbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_REPLACE_INPUT_FOCUSED),
  857. primary: 3 /* KeyCode.Enter */
  858. }
  859. }));
  860. registerEditorCommand(new FindCommand({
  861. id: FIND_IDS.ReplaceAllAction,
  862. precondition: CONTEXT_FIND_WIDGET_VISIBLE,
  863. handler: x => x.replaceAll(),
  864. kbOpts: {
  865. weight: 100 /* KeybindingWeight.EditorContrib */ + 5,
  866. kbExpr: EditorContextKeys.focus,
  867. primary: 2048 /* KeyMod.CtrlCmd */ | 512 /* KeyMod.Alt */ | 3 /* KeyCode.Enter */
  868. }
  869. }));
  870. registerEditorCommand(new FindCommand({
  871. id: FIND_IDS.ReplaceAllAction,
  872. precondition: CONTEXT_FIND_WIDGET_VISIBLE,
  873. handler: x => x.replaceAll(),
  874. kbOpts: {
  875. weight: 100 /* KeybindingWeight.EditorContrib */ + 5,
  876. kbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_REPLACE_INPUT_FOCUSED),
  877. primary: undefined,
  878. mac: {
  879. primary: 2048 /* KeyMod.CtrlCmd */ | 3 /* KeyCode.Enter */,
  880. }
  881. }
  882. }));
  883. registerEditorCommand(new FindCommand({
  884. id: FIND_IDS.SelectAllMatchesAction,
  885. precondition: CONTEXT_FIND_WIDGET_VISIBLE,
  886. handler: x => x.selectAllMatches(),
  887. kbOpts: {
  888. weight: 100 /* KeybindingWeight.EditorContrib */ + 5,
  889. kbExpr: EditorContextKeys.focus,
  890. primary: 512 /* KeyMod.Alt */ | 3 /* KeyCode.Enter */
  891. }
  892. }));