@difizen/libro-search 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/es/abstract-search-provider.d.ts +2 -1
  2. package/es/abstract-search-provider.d.ts.map +1 -1
  3. package/es/index.less +10 -8
  4. package/es/libro-search-engine-text.d.ts +1 -1
  5. package/es/libro-search-generic-provider.d.ts +5 -4
  6. package/es/libro-search-generic-provider.d.ts.map +1 -1
  7. package/es/libro-search-generic-provider.js +11 -11
  8. package/es/libro-search-manager.d.ts +1 -1
  9. package/es/libro-search-manager.d.ts.map +1 -1
  10. package/es/libro-search-manager.js +3 -3
  11. package/es/libro-search-model.d.ts +4 -4
  12. package/es/libro-search-model.d.ts.map +1 -1
  13. package/es/libro-search-model.js +19 -9
  14. package/es/libro-search-protocol.d.ts +1 -13
  15. package/es/libro-search-protocol.d.ts.map +1 -1
  16. package/es/libro-search-protocol.js +0 -5
  17. package/es/libro-search-provider.d.ts +11 -7
  18. package/es/libro-search-provider.d.ts.map +1 -1
  19. package/es/libro-search-provider.js +70 -13
  20. package/es/libro-search-utils.d.ts +1 -1
  21. package/es/libro-search-utils.d.ts.map +1 -1
  22. package/es/libro-search-utils.js +11 -7
  23. package/es/libro-search-view.d.ts +11 -11
  24. package/es/libro-search-view.d.ts.map +1 -1
  25. package/es/libro-search-view.js +136 -79
  26. package/package.json +4 -3
  27. package/src/abstract-search-provider.ts +1 -2
  28. package/src/index.less +10 -8
  29. package/src/libro-search-engine-text.ts +1 -1
  30. package/src/libro-search-generic-provider.ts +6 -6
  31. package/src/libro-search-manager.ts +4 -3
  32. package/src/libro-search-model.ts +10 -11
  33. package/src/libro-search-protocol.ts +1 -16
  34. package/src/libro-search-provider.ts +88 -41
  35. package/src/libro-search-utils.spec.ts +2 -2
  36. package/src/libro-search-utils.ts +11 -9
  37. package/src/libro-search-view.tsx +63 -43
@@ -1,3 +1,7 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ // Copyright (c) Jupyter Development Team.
3
+ // Distributed under the terms of the Modified BSD License.
4
+
1
5
  import type { Disposable } from '@difizen/mana-app';
2
6
  import { DisposableCollection, Emitter } from '@difizen/mana-app';
3
7
  import { inject, singleton } from '@difizen/mana-app';
@@ -12,15 +16,15 @@ import { LibroSearchUtils } from './libro-search-utils.js';
12
16
  */
13
17
  @singleton()
14
18
  export class LibroSearchModel implements Disposable {
15
- utils: LibroSearchUtils;
16
- protected _disposed?: boolean = false;
19
+ @inject(LibroSearchUtils) utils: LibroSearchUtils;
20
+ protected _disposed?: boolean | undefined = false;
17
21
  protected _caseSensitive = false;
18
22
  protected parsingError = '';
19
23
  protected _filters: SearchFilters = {
20
24
  searchCellOutput: true,
21
25
  onlySearchSelectedCells: false,
22
26
  };
23
- protected _replaceText = '';
27
+ protected _replaceText: string;
24
28
  protected searchDebouncer: any;
25
29
  protected _searchExpression = '';
26
30
  protected _useRegex = false;
@@ -32,19 +36,14 @@ export class LibroSearchModel implements Disposable {
32
36
  }
33
37
 
34
38
  get disposed() {
35
- return !!this._disposed;
39
+ return this._disposed;
36
40
  }
37
41
  /**
38
42
  * Search document model
39
43
  * @param searchProvider Provider for the current document
40
44
  * @param searchDebounceTime Debounce search time
41
45
  */
42
- constructor(
43
- @inject(LibroSearchUtils) utils: LibroSearchUtils,
44
- searchProvider: SearchProvider,
45
- searchDebounceTime: number,
46
- ) {
47
- this.utils = utils;
46
+ constructor(searchProvider: SearchProvider, searchDebounceTime: number) {
48
47
  this.searchProvider = searchProvider;
49
48
  // this._filters = {};
50
49
  // if (this.searchProvider.getFilters) {
@@ -227,7 +226,7 @@ export class LibroSearchModel implements Disposable {
227
226
  * @param name Filter name
228
227
  * @param v Filter value
229
228
  */
230
- async setFilter(_name: string, _v: boolean): Promise<void> {
229
+ async setFilter(name: string, v: boolean): Promise<void> {
231
230
  // if (this._filters[name] !== v) {
232
231
  // if (this.searchProvider.validateFilter) {
233
232
  // this._filters[name] = await this.searchProvider.validateFilter(name, v);
@@ -1,23 +1,8 @@
1
+ import type { SearchMatch } from '@difizen/libro-code-editor';
1
2
  import type { CellView } from '@difizen/libro-core';
2
3
  import type { Disposable, Event } from '@difizen/mana-app';
3
4
  import type { View } from '@difizen/mana-app';
4
5
  import { Syringe } from '@difizen/mana-app';
5
-
6
- /**
7
- * Base search match interface
8
- */
9
- export interface SearchMatch {
10
- /**
11
- * Text of the exact match itself
12
- */
13
- readonly text: string;
14
-
15
- /**
16
- * Start location of the match (in a text, this is the column)
17
- */
18
- position: number;
19
- }
20
-
21
6
  /**
22
7
  * HTML search match interface
23
8
  */
@@ -1,18 +1,34 @@
1
- import type { CellView } from '@difizen/libro-core';
2
- import { LibroView } from '@difizen/libro-core';
3
- import { inject, prop, transient, watch, equals } from '@difizen/mana-app';
1
+ import type { SearchMatch } from '@difizen/libro-code-editor';
2
+ import type { CellView, VirtualizedManager } from '@difizen/libro-core';
3
+ import {
4
+ EditorCellView,
5
+ LibroView,
6
+ VirtualizedManagerHelper,
7
+ } from '@difizen/libro-core';
8
+ import { inject, prop, transient, equals } from '@difizen/mana-app';
4
9
  import { Deferred, DisposableCollection } from '@difizen/mana-app';
5
10
  import { l10n } from '@difizen/mana-l10n';
6
11
 
7
12
  import { AbstractSearchProvider } from './abstract-search-provider.js';
8
13
  import { LibroCellSearchProvider } from './libro-cell-search-provider.js';
14
+ import { SearchProviderOption } from './libro-search-protocol.js';
9
15
  import type {
10
16
  CellSearchProvider,
11
17
  SearchFilter,
12
- SearchMatch,
13
18
  SearchFilters,
14
19
  } from './libro-search-protocol.js';
15
- import { SearchProviderOption } from './libro-search-protocol.js';
20
+
21
+ export function elementInViewport(el: HTMLElement): boolean {
22
+ const boundingClientRect = el.getBoundingClientRect();
23
+ return (
24
+ boundingClientRect.top >= 0 &&
25
+ boundingClientRect.bottom <=
26
+ (window.innerHeight || document.documentElement.clientHeight) &&
27
+ boundingClientRect.left >= 0 &&
28
+ boundingClientRect.right <=
29
+ (window.innerWidth || document.documentElement.clientWidth)
30
+ );
31
+ }
16
32
 
17
33
  export type LibroSearchProviderFactory = (
18
34
  option: SearchProviderOption,
@@ -44,6 +60,7 @@ export class LibroSearchProvider extends AbstractSearchProvider {
44
60
  @prop() protected providerMap = new Map<string, CellSearchProvider>();
45
61
  protected documentHasChanged = false;
46
62
  protected override view: LibroView;
63
+ protected virtualizedManager: VirtualizedManager;
47
64
 
48
65
  updateSearchCellOutput(value: boolean): void {
49
66
  this.searchCellOutput = value;
@@ -52,16 +69,20 @@ export class LibroSearchProvider extends AbstractSearchProvider {
52
69
  /**
53
70
  * @param option Provide the view to search in
54
71
  */
55
- constructor(@inject(SearchProviderOption) option: SearchProviderOption) {
72
+ constructor(
73
+ @inject(SearchProviderOption) option: SearchProviderOption,
74
+ @inject(VirtualizedManagerHelper)
75
+ virtualizedManagerHelper: VirtualizedManagerHelper,
76
+ ) {
56
77
  super(option);
57
78
  this.view = option.view as LibroView;
58
- this.toDispose.push(watch(this.view.model, 'active', this.onActiveCellChanged));
59
- this.toDispose.push(watch(this.view.model, 'cells', this.onCellsChanged));
79
+ this.virtualizedManager = virtualizedManagerHelper.getOrCreate(this.view.model);
60
80
  }
61
81
 
62
82
  protected getProvider = (cell: CellView) => {
63
83
  return this.providerMap.get(cell.id);
64
84
  };
85
+
65
86
  /**
66
87
  * Report whether or not this provider has the ability to search on the given object
67
88
  *
@@ -230,7 +251,7 @@ export class LibroSearchProvider extends AbstractSearchProvider {
230
251
  */
231
252
  startQuery = async (
232
253
  query: RegExp,
233
- _filters?: SearchFilters,
254
+ filters?: SearchFilters,
234
255
  highlightNext = true,
235
256
  ): Promise<void> => {
236
257
  if (!this.view) {
@@ -379,12 +400,11 @@ export class LibroSearchProvider extends AbstractSearchProvider {
379
400
  this.onSearchProviderChanged();
380
401
  this.cellsChangeDeferred = undefined;
381
402
  };
382
- protected onCellsChanged = async (): Promise<void> => {
403
+
404
+ onCellsChanged = async (): Promise<void> => {
383
405
  if (!this.cellsChangeDeferred) {
384
406
  this.cellsChangeDeferred = new Deferred();
385
- this.cellsChangeDeferred.promise.then(this.doCellsChanged).catch(() => {
386
- //
387
- });
407
+ this.cellsChangeDeferred.promise.then(this.doCellsChanged).catch(console.error);
388
408
  this.cellsChangeDeferred.resolve();
389
409
  }
390
410
  };
@@ -401,35 +421,62 @@ export class LibroSearchProvider extends AbstractSearchProvider {
401
421
  }
402
422
  return index;
403
423
  };
424
+
425
+ protected selectCell(selectIndex: number) {
426
+ if (selectIndex >= 0 && selectIndex < this.view.model.cells.length - 1) {
427
+ this.view.model.selectCell(this.view.model.cells[selectIndex]);
428
+ }
429
+ }
430
+
404
431
  protected stepNext = async (
405
432
  reverse = false,
406
433
  loop = false,
407
434
  ): Promise<SearchMatch | undefined> => {
408
- const activateNewMatch = async () => {
409
- // if (this.getActiveIndex() !== this._currentProviderIndex!) {
410
- // this.widget.content.activeCellIndex = this._currentProviderIndex!;
411
- // }
412
- // const activeCell = this.view.activeCell;
413
- // if (!activeCell.inViewport) {
414
- // try {
415
- // if (this.view.activeCell) {
416
- // this.view.model.scrollToView(this.view.activeCell);
417
- // }
418
- // } catch (error) {
419
- // // no-op
420
- // }
421
- // }
422
- // // Unhide cell
423
- // if (activeCell.inputHidden) {
424
- // activeCell.inputHidden = false;
425
- // }
426
- // if (!activeCell.inViewport) {
427
- // // It will not be possible the cell is not in the view
428
- // return;
429
- // }
430
- // await activeCell.ready;
431
- // const editor = activeCell.editor! as CodeMirrorEditor;
432
- // editor.revealSelection(editor.getSelection());
435
+ const activateNewMatch = async (match: SearchMatch) => {
436
+ if (this.getActiveIndex() !== this.currentProviderIndex!) {
437
+ this.selectCell(this.currentProviderIndex!);
438
+ }
439
+ const activeCell = this.view.activeCell;
440
+
441
+ if (!activeCell) {
442
+ return;
443
+ }
444
+
445
+ const node = activeCell.container?.current;
446
+
447
+ if (!elementInViewport(node!)) {
448
+ try {
449
+ if (this.view.activeCell) {
450
+ if (this.virtualizedManager.isVirtualized) {
451
+ if (EditorCellView.is(activeCell)) {
452
+ const line = activeCell.editor?.getPositionAt(match.position)?.line;
453
+
454
+ this.view.model.scrollToCellView({
455
+ cellIndex: this.view.activeCellIndex,
456
+ lineIndex: line,
457
+ });
458
+ }
459
+ } else {
460
+ this.view.model.scrollToView(this.view.activeCell);
461
+ }
462
+ }
463
+ } catch (error) {
464
+ // no-op
465
+ }
466
+ }
467
+ // Unhide cell
468
+ if (activeCell.hasInputHidden) {
469
+ activeCell.hasInputHidden = false;
470
+ }
471
+ if (!elementInViewport(node!)) {
472
+ // It will not be possible the cell is not in the view
473
+ return;
474
+ }
475
+ if (EditorCellView.is(activeCell)) {
476
+ // await activeCell.editor;
477
+ const editor = activeCell.editor;
478
+ editor?.revealSelection(editor.getSelection());
479
+ }
433
480
  };
434
481
  if (this.currentProviderIndex === undefined) {
435
482
  this.currentProviderIndex = this.getActiveIndex()!;
@@ -441,7 +488,7 @@ export class LibroSearchProvider extends AbstractSearchProvider {
441
488
  ? await searchEngine?.highlightPrevious()
442
489
  : await searchEngine?.highlightNext();
443
490
  if (match) {
444
- await activateNewMatch();
491
+ await activateNewMatch(match);
445
492
  return match;
446
493
  } else {
447
494
  this.currentProviderIndex = this.currentProviderIndex + (reverse ? -1 : 1);
@@ -469,7 +516,7 @@ export class LibroSearchProvider extends AbstractSearchProvider {
469
516
  : await searchEngine?.highlightNext();
470
517
 
471
518
  if (match) {
472
- await activateNewMatch();
519
+ await activateNewMatch(match);
473
520
  return match;
474
521
  }
475
522
  }
@@ -478,7 +525,7 @@ export class LibroSearchProvider extends AbstractSearchProvider {
478
525
  return undefined;
479
526
  };
480
527
 
481
- protected onActiveCellChanged = async () => {
528
+ onActiveCellChanged = async () => {
482
529
  await this._onSelectionChanged();
483
530
 
484
531
  if (this.getActiveIndex() !== this.currentProviderIndex) {
@@ -1,7 +1,7 @@
1
- import 'reflect-metadata';
2
1
  import assert from 'assert';
3
2
 
4
- import type { SearchMatch } from './libro-search-protocol.js';
3
+ import type { SearchMatch } from '@difizen/libro-code-editor';
4
+
5
5
  import { LibroSearchUtils } from './libro-search-utils.js';
6
6
 
7
7
  describe('libro search utils', () => {
@@ -1,7 +1,6 @@
1
+ import type { SearchMatch } from '@difizen/libro-code-editor';
1
2
  import { singleton } from '@difizen/mana-app';
2
3
 
3
- import type { SearchMatch } from './libro-search-protocol.js';
4
-
5
4
  /**
6
5
  * Search Utils
7
6
  */
@@ -69,15 +68,18 @@ export class LibroSearchUtils {
69
68
  const queryText = regex
70
69
  ? queryString
71
70
  : queryString.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
72
- const ret = new RegExp(queryText, flag);
71
+ try {
72
+ const ret = new RegExp(queryText, flag);
73
+ // If the empty string is hit, the search logic will freeze the browser tab
74
+ // Trying /^/ or /$/ on the codemirror search demo, does not find anything.
75
+ // So this is a limitation of the editor.
76
+ if (ret.test('')) {
77
+ return undefined;
78
+ }
73
79
 
74
- // If the empty string is hit, the search logic will freeze the browser tab
75
- // Trying /^/ or /$/ on the codemirror search demo, does not find anything.
76
- // So this is a limitation of the editor.
77
- if (ret.test('')) {
80
+ return ret;
81
+ } catch (error) {
78
82
  return undefined;
79
83
  }
80
-
81
- return ret;
82
84
  }
83
85
  }
@@ -1,22 +1,21 @@
1
1
  import {
2
- RightOutlined,
3
- ArrowUpOutlined,
4
2
  ArrowDownOutlined,
5
- EllipsisOutlined,
3
+ ArrowUpOutlined,
6
4
  CloseOutlined,
7
5
  createFromIconfontCN,
6
+ EllipsisOutlined,
7
+ RightOutlined,
8
8
  } from '@ant-design/icons';
9
9
  import type { LibroView } from '@difizen/libro-core';
10
10
  import { LirboContextKey } from '@difizen/libro-core';
11
- import { prop, useInject } from '@difizen/mana-app';
11
+ import { prop, useInject, watch } from '@difizen/mana-app';
12
12
  import { BaseView, view, ViewInstance } from '@difizen/mana-app';
13
13
  import { inject, transient } from '@difizen/mana-app';
14
14
  import { l10n } from '@difizen/mana-l10n';
15
- import { Input, Button, Checkbox, Tag } from 'antd';
15
+ import { Button, Checkbox, Input, Tag } from 'antd';
16
16
  import type { CheckboxChangeEvent } from 'antd/es/checkbox';
17
17
  import type { InputRef } from 'antd/es/input';
18
18
  import classnames from 'classnames';
19
- import type { FC } from 'react';
20
19
  import { forwardRef, useEffect, useRef } from 'react';
21
20
 
22
21
  import type { LibroSearchProvider } from './libro-search-provider.js';
@@ -27,7 +26,7 @@ const IconFont = createFromIconfontCN({
27
26
  scriptUrl: '//at.alicdn.com/t/a/font_3381673_65wfctnq7rt.js',
28
27
  });
29
28
 
30
- export const ReplaceToggle: FC = () => {
29
+ export const ReplaceToggle = () => {
31
30
  const instance = useInject<LibroSearchView>(ViewInstance);
32
31
  return (
33
32
  <div className="libro-search-replace-toggle" onClick={instance.toggleReplace}>
@@ -41,16 +40,24 @@ export const ReplaceToggle: FC = () => {
41
40
  );
42
41
  };
43
42
 
44
- export const SearchIndex: FC = () => {
43
+ export const SearchIndex = () => {
45
44
  const instance = useInject<LibroSearchView>(ViewInstance);
45
+
46
+ // TODO: trigger update when current match index changed, matchesCount dont work
47
+ useEffect(() => {
48
+ //
49
+ }, [instance.currentMatchIndex]);
50
+
46
51
  return (
47
52
  <div className="libro-search-index">
48
- {instance.currentMatchIndex ?? '-'}/{instance.matchesCount ?? '-'}
53
+ {instance.matchesCount !== undefined
54
+ ? `${instance.currentMatchIndex}/${instance.matchesCount}`
55
+ : '无结果'}
49
56
  </div>
50
57
  );
51
58
  };
52
59
 
53
- export const SearchContent: FC = () => {
60
+ export const SearchContent = () => {
54
61
  const instance = useInject<LibroSearchView>(ViewInstance);
55
62
  const findInputRef = useRef<InputRef>(null);
56
63
  useEffect(() => {
@@ -67,6 +74,7 @@ export const SearchContent: FC = () => {
67
74
  }
68
75
  return;
69
76
  }, [instance]);
77
+
70
78
  return (
71
79
  <div
72
80
  className="libro-search-content"
@@ -81,6 +89,7 @@ export const SearchContent: FC = () => {
81
89
  value={instance.findStr}
82
90
  onChange={instance.handleFindChange}
83
91
  size="small"
92
+ placeholder="搜索"
84
93
  suffix={
85
94
  <span className="libro-search-input-suffix">
86
95
  <IconFont
@@ -89,6 +98,7 @@ export const SearchContent: FC = () => {
89
98
  })}
90
99
  onClick={instance.toggleCaseSensitive}
91
100
  type="icon-Aa"
101
+ title="Match Case"
92
102
  />
93
103
 
94
104
  <IconFont
@@ -97,6 +107,7 @@ export const SearchContent: FC = () => {
97
107
  })}
98
108
  onClick={instance.toggleUseRegex}
99
109
  type="icon-zhengzeshi"
110
+ title="Use Regular Expression"
100
111
  />
101
112
  </span>
102
113
  }
@@ -106,11 +117,13 @@ export const SearchContent: FC = () => {
106
117
  <SearchIndex />
107
118
  <div>
108
119
  <Button
120
+ title="Previous Match"
109
121
  onClick={instance.previous}
110
122
  icon={<ArrowUpOutlined />}
111
123
  size="small"
112
124
  />
113
125
  <Button
126
+ title="Next Match"
114
127
  onClick={instance.next}
115
128
  icon={<ArrowDownOutlined />}
116
129
  size="small"
@@ -131,6 +144,7 @@ export const SearchContent: FC = () => {
131
144
  value={instance.replaceStr}
132
145
  onChange={instance.handleReplaceChange}
133
146
  size="small"
147
+ placeholder="替换"
134
148
  />
135
149
  </td>
136
150
  <td className="libro-search-action">
@@ -139,12 +153,14 @@ export const SearchContent: FC = () => {
139
153
  onClick={instance.replace}
140
154
  icon={<IconFont type="icon-zifuchuantihuan_2" />}
141
155
  size="small"
156
+ title="Replace"
142
157
  />
143
158
 
144
159
  <Button
145
160
  onClick={instance.replaceAll}
146
161
  icon={<IconFont type="icon-tihuantupian" />}
147
162
  size="small"
163
+ title="Replace All"
148
164
  />
149
165
  </div>
150
166
  </td>
@@ -171,7 +187,7 @@ export const SearchContent: FC = () => {
171
187
  };
172
188
  // TODO: 更改图标
173
189
  export const SearchComponent = forwardRef<HTMLDivElement>(function SearchComponent(
174
- _props: { top?: number },
190
+ props: { top?: number },
175
191
  ref,
176
192
  ) {
177
193
  const instance = useInject<LibroSearchView>(ViewInstance);
@@ -193,41 +209,18 @@ export const SearchComponent = forwardRef<HTMLDivElement>(function SearchCompone
193
209
  @view('libro-search-view')
194
210
  export class LibroSearchView extends BaseView {
195
211
  findInputRef?: React.RefObject<InputRef> | null;
196
- contextKey: LirboContextKey;
197
- utils: LibroSearchUtils;
198
- searchProviderFactory: LibroSearchProviderFactory;
199
-
200
- constructor(
201
- @inject(LirboContextKey) contextKey: LirboContextKey,
202
- @inject(LibroSearchUtils) utils: LibroSearchUtils,
203
- @inject(LibroSearchProviderFactory)
204
- searchProviderFactory: LibroSearchProviderFactory,
205
- ) {
206
- super();
207
- this.contextKey = contextKey;
208
- this.utils = utils;
209
- this.searchProviderFactory = searchProviderFactory;
210
- }
211
-
212
- protected _libro?: LibroView;
213
-
214
- get libro(): LibroView | undefined {
215
- return this._libro;
216
- }
217
-
218
- set libro(value: LibroView | undefined) {
219
- this._libro = value;
220
- this.searchProvider = this.searchProviderFactory({ view: this.libro! });
221
- }
222
-
212
+ @inject(LirboContextKey) contextKey: LirboContextKey;
213
+ @inject(LibroSearchUtils) utils: LibroSearchUtils;
214
+ @inject(LibroSearchProviderFactory) searchProviderFactory: LibroSearchProviderFactory;
215
+ libro?: LibroView;
223
216
  @prop() searchProvider?: LibroSearchProvider;
224
217
  @prop() searchVisible = false;
225
218
  get replaceVisible(): boolean {
226
219
  return this.searchProvider?.replaceMode ?? false;
227
220
  }
228
221
  @prop() settingVisible = false;
229
- @prop() findStr?: string | undefined = undefined;
230
- @prop() lastSearch?: string | undefined = undefined;
222
+ @prop() findStr?: string = undefined;
223
+ @prop() lastSearch?: string = undefined;
231
224
  @prop() replaceStr = '';
232
225
  @prop() caseSensitive = false;
233
226
  @prop() useRegex = false;
@@ -255,8 +248,31 @@ export class LibroSearchView extends BaseView {
255
248
  return this.searchProvider?.matchesCount;
256
249
  }
257
250
 
258
- onviewWillUnmount = () => {
259
- this.searchProvider?.endQuery();
251
+ override onViewMount = () => {
252
+ if (!this.searchProvider && this.libro) {
253
+ this.searchProvider = this.searchProviderFactory({ view: this.libro });
254
+ this.toDispose.push(watch(this.libro.model, 'active', this.onActiveCellChanged));
255
+ this.toDispose.push(
256
+ this.libro.model.onSourceChanged(() => this.onCellsChanged()),
257
+ );
258
+ }
259
+ };
260
+
261
+ onActiveCellChanged = () => {
262
+ if (this.searchVisible) {
263
+ this.searchProvider?.onActiveCellChanged();
264
+ }
265
+ };
266
+
267
+ onCellsChanged = () => {
268
+ if (this.searchVisible) {
269
+ this.searchProvider?.onCellsChanged();
270
+ }
271
+ };
272
+
273
+ onviewWillUnmount = async () => {
274
+ await this.searchProvider?.endQuery();
275
+ this.searchProvider?.dispose();
260
276
  };
261
277
 
262
278
  show = () => {
@@ -269,6 +285,9 @@ export class LibroSearchView extends BaseView {
269
285
  this.searchVisible = false;
270
286
  this.contextKey.enableCommandMode();
271
287
  this.searchProvider?.endQuery();
288
+ if (this.searchProvider) {
289
+ this.searchProvider.replaceMode = false;
290
+ }
272
291
  this.libro?.focus();
273
292
  };
274
293
 
@@ -316,6 +335,7 @@ export class LibroSearchView extends BaseView {
316
335
 
317
336
  toggleUseRegex = () => {
318
337
  this.useRegex = !this.useRegex;
338
+ this.search();
319
339
  };
320
340
 
321
341
  next = () => {
@@ -342,8 +362,8 @@ export class LibroSearchView extends BaseView {
342
362
  const init = this.searchProvider?.getInitialQuery();
343
363
  if (init) {
344
364
  this.findStr = init;
345
- this.search(false);
346
365
  }
366
+ this.search(false);
347
367
  };
348
368
  getHeaderHeight = () => {
349
369
  let height = 32;