@jupyterlab/codemirror 4.0.0-alpha.20 → 4.0.0-alpha.22
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.
- package/lib/extension.js +11 -2
- package/lib/extension.js.map +1 -1
- package/lib/extensions/ybinding.d.ts +6 -2
- package/lib/extensions/ybinding.js +18 -2
- package/lib/extensions/ybinding.js.map +1 -1
- package/lib/language.d.ts +1 -1
- package/lib/language.js +9 -12
- package/lib/language.js.map +1 -1
- package/lib/searchprovider.d.ts +27 -5
- package/lib/searchprovider.js +154 -64
- package/lib/searchprovider.js.map +1 -1
- package/package.json +12 -12
- package/src/extension.ts +14 -2
- package/src/extensions/ybinding.ts +31 -3
- package/src/language.ts +10 -13
- package/src/searchprovider.ts +190 -77
- package/style/base.css +16 -4
package/src/searchprovider.ts
CHANGED
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
33
|
import { ISearchMatch } from '@jupyterlab/documentsearch';
|
|
34
|
-
import { JSONExt } from '@lumino/coreutils';
|
|
35
34
|
import { CodeMirrorEditor } from './editor';
|
|
36
35
|
import { StateEffect, StateEffectType, StateField } from '@codemirror/state';
|
|
37
36
|
import { Decoration, DecorationSet, EditorView } from '@codemirror/view';
|
|
@@ -60,6 +59,7 @@ export abstract class EditorSearchProvider<
|
|
|
60
59
|
this.currentIndex = null;
|
|
61
60
|
this._stateChanged = new Signal<IBaseSearchProvider, void>(this);
|
|
62
61
|
}
|
|
62
|
+
|
|
63
63
|
/**
|
|
64
64
|
* CodeMirror search highlighter
|
|
65
65
|
*/
|
|
@@ -153,9 +153,10 @@ export abstract class EditorSearchProvider<
|
|
|
153
153
|
* @param v New value
|
|
154
154
|
*/
|
|
155
155
|
async setIsActive(v: boolean): Promise<void> {
|
|
156
|
-
if (this._isActive
|
|
157
|
-
|
|
156
|
+
if (this._isActive === v) {
|
|
157
|
+
return;
|
|
158
158
|
}
|
|
159
|
+
this._isActive = v;
|
|
159
160
|
if (this._isActive) {
|
|
160
161
|
if (this.query !== null) {
|
|
161
162
|
await this.startQuery(this.query, this.filters);
|
|
@@ -165,6 +166,18 @@ export abstract class EditorSearchProvider<
|
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Set whether search should be limitted to specified selection.
|
|
171
|
+
*/
|
|
172
|
+
async setSearchSelection(selection: CodeEditor.IRange | null): Promise<void> {
|
|
173
|
+
if (this._inSelection === selection) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
this._inSelection = selection;
|
|
177
|
+
await this.updateCodeMirror(this.model.sharedModel.getSource());
|
|
178
|
+
this._stateChanged.emit();
|
|
179
|
+
}
|
|
180
|
+
|
|
168
181
|
/**
|
|
169
182
|
* Initialize the search using the provided options. Should update the UI
|
|
170
183
|
* to highlight all matches and "select" the first match.
|
|
@@ -186,6 +199,7 @@ export abstract class EditorSearchProvider<
|
|
|
186
199
|
* Stop the search and clean any UI elements.
|
|
187
200
|
*/
|
|
188
201
|
async endQuery(): Promise<void> {
|
|
202
|
+
await this.clearHighlight();
|
|
189
203
|
await this.cmHandler.endQuery();
|
|
190
204
|
this.currentIndex = null;
|
|
191
205
|
}
|
|
@@ -195,15 +209,21 @@ export abstract class EditorSearchProvider<
|
|
|
195
209
|
*
|
|
196
210
|
* @returns The next match if there is one.
|
|
197
211
|
*/
|
|
198
|
-
async highlightNext(
|
|
212
|
+
async highlightNext(
|
|
213
|
+
loop = true,
|
|
214
|
+
fromCursor = false
|
|
215
|
+
): Promise<ISearchMatch | undefined> {
|
|
199
216
|
if (this.matchesCount === 0 || !this.isActive) {
|
|
200
217
|
this.currentIndex = null;
|
|
201
218
|
} else {
|
|
202
|
-
// This starts from the cursor position
|
|
203
|
-
let match = await this.cmHandler.highlightNext();
|
|
219
|
+
// This starts from the cursor position if `fromCursor` is true
|
|
220
|
+
let match = await this.cmHandler.highlightNext(fromCursor);
|
|
204
221
|
if (match) {
|
|
205
222
|
this.currentIndex = this.cmHandler.currentIndex;
|
|
206
223
|
} else {
|
|
224
|
+
// Note: the loop logic is only used in single-editor (e.g. file editor)
|
|
225
|
+
// provider sub-classes, notebook has it's own loop logic and ignores
|
|
226
|
+
// `currentIndex` as set here.
|
|
207
227
|
this.currentIndex = loop ? 0 : null;
|
|
208
228
|
}
|
|
209
229
|
return match;
|
|
@@ -217,12 +237,15 @@ export abstract class EditorSearchProvider<
|
|
|
217
237
|
*
|
|
218
238
|
* @returns The previous match if there is one.
|
|
219
239
|
*/
|
|
220
|
-
async highlightPrevious(
|
|
240
|
+
async highlightPrevious(
|
|
241
|
+
loop = true,
|
|
242
|
+
fromCursor = false
|
|
243
|
+
): Promise<ISearchMatch | undefined> {
|
|
221
244
|
if (this.matchesCount === 0 || !this.isActive) {
|
|
222
245
|
this.currentIndex = null;
|
|
223
246
|
} else {
|
|
224
|
-
// This starts from the cursor position
|
|
225
|
-
let match = await this.cmHandler.highlightPrevious();
|
|
247
|
+
// This starts from the cursor position if `fromCursor` is true
|
|
248
|
+
let match = await this.cmHandler.highlightPrevious(fromCursor);
|
|
226
249
|
if (match) {
|
|
227
250
|
this.currentIndex = this.cmHandler.currentIndex;
|
|
228
251
|
} else {
|
|
@@ -239,6 +262,13 @@ export abstract class EditorSearchProvider<
|
|
|
239
262
|
*
|
|
240
263
|
* If no match is selected, it won't do anything.
|
|
241
264
|
*
|
|
265
|
+
* The caller of this method is expected to call `highlightNext` if after
|
|
266
|
+
* calling `replaceCurrentMatch()` attribute `this.currentIndex` is null.
|
|
267
|
+
* It is necesary to let the caller handle highlighting because this
|
|
268
|
+
* method is used in composition pattern (search engine of notebook cells)
|
|
269
|
+
* and highligthing on the composer (notebook) level needs to switch to next
|
|
270
|
+
* engine (cell) with matches.
|
|
271
|
+
*
|
|
242
272
|
* @param newText The replacement text.
|
|
243
273
|
* @returns Whether a replace occurred.
|
|
244
274
|
*/
|
|
@@ -257,19 +287,16 @@ export abstract class EditorSearchProvider<
|
|
|
257
287
|
this.currentIndex !== null &&
|
|
258
288
|
this.currentIndex < this.cmHandler.matches.length
|
|
259
289
|
) {
|
|
260
|
-
const editor = this.editor as CodeMirrorEditor;
|
|
261
|
-
const selection = editor.state.sliceDoc(
|
|
262
|
-
editor.state.selection.main.from,
|
|
263
|
-
editor.state.selection.main.to
|
|
264
|
-
);
|
|
265
290
|
const match = this.getCurrentMatch();
|
|
266
|
-
// If cursor is
|
|
267
|
-
if (
|
|
291
|
+
// If cursor there is no match selected, highlight the next match
|
|
292
|
+
if (!match) {
|
|
268
293
|
this.currentIndex = null;
|
|
269
|
-
// The next will be highlighted as a consequence of this returning false
|
|
270
294
|
} else {
|
|
271
295
|
this.cmHandler.matches.splice(this.currentIndex, 1);
|
|
272
|
-
this.currentIndex =
|
|
296
|
+
this.currentIndex =
|
|
297
|
+
this.currentIndex < this.cmHandler.matches.length
|
|
298
|
+
? Math.max(this.currentIndex - 1, 0)
|
|
299
|
+
: null;
|
|
273
300
|
const substitutedText = options?.regularExpression
|
|
274
301
|
? match!.text.replace(this.query!, newText)
|
|
275
302
|
: newText;
|
|
@@ -332,7 +359,7 @@ export abstract class EditorSearchProvider<
|
|
|
332
359
|
*
|
|
333
360
|
* @returns The current match
|
|
334
361
|
*/
|
|
335
|
-
|
|
362
|
+
getCurrentMatch(): ISearchMatch | undefined {
|
|
336
363
|
if (this.currentIndex === null) {
|
|
337
364
|
return undefined;
|
|
338
365
|
} else {
|
|
@@ -365,10 +392,25 @@ export abstract class EditorSearchProvider<
|
|
|
365
392
|
*/
|
|
366
393
|
protected async updateCodeMirror(content: string) {
|
|
367
394
|
if (this.query !== null && this.isActive) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
395
|
+
const allMatches = await TextSearchEngine.search(this.query, content);
|
|
396
|
+
if (this._inSelection) {
|
|
397
|
+
const editor = this.editor!;
|
|
398
|
+
const start = editor.getOffsetAt(this._inSelection.start);
|
|
399
|
+
const end = editor.getOffsetAt(this._inSelection.end);
|
|
400
|
+
this.cmHandler.matches = allMatches.filter(
|
|
401
|
+
match => match.position >= start && match.position <= end
|
|
402
|
+
);
|
|
403
|
+
// A special case to always have a current match when in line selection mode.
|
|
404
|
+
if (
|
|
405
|
+
this.cmHandler.currentIndex === null &&
|
|
406
|
+
this.cmHandler.matches.length > 0
|
|
407
|
+
) {
|
|
408
|
+
await this.cmHandler.highlightNext(true, false);
|
|
409
|
+
}
|
|
410
|
+
this.currentIndex = this.cmHandler.currentIndex;
|
|
411
|
+
} else {
|
|
412
|
+
this.cmHandler.matches = allMatches;
|
|
413
|
+
}
|
|
372
414
|
} else {
|
|
373
415
|
this.cmHandler.matches = [];
|
|
374
416
|
}
|
|
@@ -389,15 +431,31 @@ export abstract class EditorSearchProvider<
|
|
|
389
431
|
// Needs to be protected so subclass can emit the signal too.
|
|
390
432
|
protected _stateChanged: Signal<IBaseSearchProvider, void>;
|
|
391
433
|
private _isActive = true;
|
|
434
|
+
private _inSelection: CodeEditor.IRange | null = null;
|
|
392
435
|
private _isDisposed = false;
|
|
393
436
|
private _cmHandler: CodeMirrorSearchHighlighter | null = null;
|
|
394
437
|
}
|
|
395
438
|
|
|
439
|
+
/**
|
|
440
|
+
* Matches to be highlighted.
|
|
441
|
+
*/
|
|
442
|
+
interface IEffectValue {
|
|
443
|
+
matches: ISearchMatch[];
|
|
444
|
+
currentMatch: ISearchMatch | null;
|
|
445
|
+
}
|
|
446
|
+
|
|
396
447
|
/**
|
|
397
448
|
* Helper class to highlight texts in a code mirror editor.
|
|
398
449
|
*
|
|
399
450
|
* Highlighted texts (aka `matches`) must be provided through
|
|
400
451
|
* the `matches` attributes.
|
|
452
|
+
*
|
|
453
|
+
* **NOTES:**
|
|
454
|
+
* - to retain the selection visibility `drawSelection` extension is needed.
|
|
455
|
+
* - highlighting starts from the cursor (if editor is focused, cursor moved,
|
|
456
|
+
* or `fromCursor` argument is set to `true`), or from last "current" match
|
|
457
|
+
* otherwise.
|
|
458
|
+
* - `currentIndex` is the (readonly) source of truth for the current match.
|
|
401
459
|
*/
|
|
402
460
|
export class CodeMirrorSearchHighlighter {
|
|
403
461
|
/**
|
|
@@ -410,15 +468,22 @@ export class CodeMirrorSearchHighlighter {
|
|
|
410
468
|
this._matches = new Array<ISearchMatch>();
|
|
411
469
|
this._currentIndex = null;
|
|
412
470
|
|
|
413
|
-
this._highlightEffect = StateEffect.define<
|
|
414
|
-
map: (value, mapping) =>
|
|
415
|
-
|
|
471
|
+
this._highlightEffect = StateEffect.define<IEffectValue>({
|
|
472
|
+
map: (value, mapping) => {
|
|
473
|
+
const transform = (v: ISearchMatch) => ({
|
|
416
474
|
text: v.text,
|
|
417
475
|
position: mapping.mapPos(v.position)
|
|
418
|
-
})
|
|
419
|
-
|
|
476
|
+
});
|
|
477
|
+
return {
|
|
478
|
+
matches: value.matches.map(transform),
|
|
479
|
+
currentMatch: value.currentMatch
|
|
480
|
+
? transform(value.currentMatch)
|
|
481
|
+
: null
|
|
482
|
+
};
|
|
483
|
+
}
|
|
420
484
|
});
|
|
421
485
|
this._highlightMark = Decoration.mark({ class: 'cm-searching' });
|
|
486
|
+
this._currentMark = Decoration.mark({ class: 'jp-current-match' });
|
|
422
487
|
|
|
423
488
|
this._highlightField = StateField.define<DecorationSet>({
|
|
424
489
|
create: () => {
|
|
@@ -428,7 +493,7 @@ export class CodeMirrorSearchHighlighter {
|
|
|
428
493
|
highlights = highlights.map(transaction.changes);
|
|
429
494
|
for (let ef of transaction.effects) {
|
|
430
495
|
if (ef.is(this._highlightEffect)) {
|
|
431
|
-
const e = ef as StateEffect<
|
|
496
|
+
const e = ef as StateEffect<IEffectValue>;
|
|
432
497
|
if (e.value.matches.length) {
|
|
433
498
|
highlights = highlights.update({
|
|
434
499
|
add: e.value.matches.map(m =>
|
|
@@ -440,6 +505,17 @@ export class CodeMirrorSearchHighlighter {
|
|
|
440
505
|
// filter out old marks
|
|
441
506
|
filter: () => false
|
|
442
507
|
});
|
|
508
|
+
highlights = highlights.update({
|
|
509
|
+
add: e.value.currentMatch
|
|
510
|
+
? [
|
|
511
|
+
this._currentMark.range(
|
|
512
|
+
e.value.currentMatch.position,
|
|
513
|
+
e.value.currentMatch.position +
|
|
514
|
+
e.value.currentMatch.text.length
|
|
515
|
+
)
|
|
516
|
+
]
|
|
517
|
+
: []
|
|
518
|
+
});
|
|
443
519
|
} else {
|
|
444
520
|
highlights = Decoration.none;
|
|
445
521
|
}
|
|
@@ -465,12 +541,18 @@ export class CodeMirrorSearchHighlighter {
|
|
|
465
541
|
return this._matches;
|
|
466
542
|
}
|
|
467
543
|
set matches(v: ISearchMatch[]) {
|
|
468
|
-
|
|
469
|
-
|
|
544
|
+
this._matches = v;
|
|
545
|
+
if (
|
|
546
|
+
this._currentIndex !== null &&
|
|
547
|
+
this._currentIndex > this._matches.length
|
|
548
|
+
) {
|
|
549
|
+
this._currentIndex = this._matches.length > 0 ? 0 : null;
|
|
470
550
|
}
|
|
471
|
-
this.
|
|
551
|
+
this._highlightCurrentMatch(true);
|
|
472
552
|
}
|
|
473
553
|
|
|
554
|
+
private _current: ISearchMatch | null = null;
|
|
555
|
+
|
|
474
556
|
/**
|
|
475
557
|
* Clear all highlighted matches
|
|
476
558
|
*/
|
|
@@ -488,17 +570,8 @@ export class CodeMirrorSearchHighlighter {
|
|
|
488
570
|
|
|
489
571
|
if (this._cm) {
|
|
490
572
|
this._cm.editor.dispatch({
|
|
491
|
-
effects: this._highlightEffect.of({ matches: [] })
|
|
573
|
+
effects: this._highlightEffect.of({ matches: [], currentMatch: null })
|
|
492
574
|
});
|
|
493
|
-
|
|
494
|
-
const selection = this._cm.state.selection.main;
|
|
495
|
-
const from = selection.from;
|
|
496
|
-
const to = selection.to;
|
|
497
|
-
// Setting a reverse selection to allow search-as-you-type to maintain the
|
|
498
|
-
// current selected match. See comment in _findNext for more details.
|
|
499
|
-
if (from !== to) {
|
|
500
|
-
this._cm.editor.dispatch({ selection: { anchor: to, head: from } });
|
|
501
|
-
}
|
|
502
575
|
}
|
|
503
576
|
|
|
504
577
|
return Promise.resolve();
|
|
@@ -509,9 +582,12 @@ export class CodeMirrorSearchHighlighter {
|
|
|
509
582
|
*
|
|
510
583
|
* @returns The next match if available
|
|
511
584
|
*/
|
|
512
|
-
highlightNext(
|
|
513
|
-
|
|
514
|
-
|
|
585
|
+
highlightNext(
|
|
586
|
+
fromCursor = false,
|
|
587
|
+
doNotModifySelection = false
|
|
588
|
+
): Promise<ISearchMatch | undefined> {
|
|
589
|
+
this._currentIndex = this._findNext(false, fromCursor);
|
|
590
|
+
this._highlightCurrentMatch(doNotModifySelection);
|
|
515
591
|
return Promise.resolve(
|
|
516
592
|
this._currentIndex !== null
|
|
517
593
|
? this._matches[this._currentIndex]
|
|
@@ -524,8 +600,8 @@ export class CodeMirrorSearchHighlighter {
|
|
|
524
600
|
*
|
|
525
601
|
* @returns The previous match if available
|
|
526
602
|
*/
|
|
527
|
-
highlightPrevious(): Promise<ISearchMatch | undefined> {
|
|
528
|
-
this._currentIndex = this._findNext(true);
|
|
603
|
+
highlightPrevious(fromCursor = false): Promise<ISearchMatch | undefined> {
|
|
604
|
+
this._currentIndex = this._findNext(true, fromCursor);
|
|
529
605
|
this._highlightCurrentMatch();
|
|
530
606
|
return Promise.resolve(
|
|
531
607
|
this._currentIndex !== null
|
|
@@ -544,14 +620,39 @@ export class CodeMirrorSearchHighlighter {
|
|
|
544
620
|
throw new Error('CodeMirrorEditor already set.');
|
|
545
621
|
} else {
|
|
546
622
|
this._cm = editor;
|
|
547
|
-
this._refresh();
|
|
548
623
|
if (this._currentIndex !== null) {
|
|
549
624
|
this._highlightCurrentMatch();
|
|
550
625
|
}
|
|
626
|
+
this._refresh();
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
private _selectCurrentMatch(): void {
|
|
631
|
+
const match = this._current;
|
|
632
|
+
if (!match) {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
if (!this._cm) {
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
const selection = this._cm.editor.state.selection.main;
|
|
639
|
+
if (
|
|
640
|
+
selection.from === match.position &&
|
|
641
|
+
selection.to === match.position + match.text.length
|
|
642
|
+
) {
|
|
643
|
+
return;
|
|
551
644
|
}
|
|
645
|
+
const cursor = {
|
|
646
|
+
anchor: match.position,
|
|
647
|
+
head: match.position + match.text.length
|
|
648
|
+
};
|
|
649
|
+
this._cm.editor.dispatch({
|
|
650
|
+
selection: cursor,
|
|
651
|
+
scrollIntoView: true
|
|
652
|
+
});
|
|
552
653
|
}
|
|
553
654
|
|
|
554
|
-
private _highlightCurrentMatch(): void {
|
|
655
|
+
private _highlightCurrentMatch(doNotModifySelection = false): void {
|
|
555
656
|
if (!this._cm) {
|
|
556
657
|
// no-op
|
|
557
658
|
return;
|
|
@@ -560,18 +661,23 @@ export class CodeMirrorSearchHighlighter {
|
|
|
560
661
|
// Highlight the current index
|
|
561
662
|
if (this._currentIndex !== null) {
|
|
562
663
|
const match = this.matches[this._currentIndex];
|
|
563
|
-
this.
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
664
|
+
this._current = match;
|
|
665
|
+
// Do not change selection/scroll if user is selecting
|
|
666
|
+
if (!doNotModifySelection) {
|
|
667
|
+
if (this._cm.hasFocus()) {
|
|
668
|
+
// If editor is focused we actually set the cursor on the match.
|
|
669
|
+
this._selectCurrentMatch();
|
|
670
|
+
} else {
|
|
671
|
+
// otherwise we just scroll to preserve the selection.
|
|
672
|
+
this._cm.editor.dispatch({
|
|
673
|
+
effects: EditorView.scrollIntoView(match.position)
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
}
|
|
571
677
|
} else {
|
|
572
|
-
|
|
573
|
-
this._cm.editor.dispatch({ selection: { anchor: 0 } });
|
|
678
|
+
this._current = null;
|
|
574
679
|
}
|
|
680
|
+
this._refresh();
|
|
575
681
|
}
|
|
576
682
|
|
|
577
683
|
private _refresh(): void {
|
|
@@ -579,35 +685,41 @@ export class CodeMirrorSearchHighlighter {
|
|
|
579
685
|
// no-op
|
|
580
686
|
return;
|
|
581
687
|
}
|
|
582
|
-
|
|
583
688
|
let effects: StateEffect<unknown>[] = [
|
|
584
|
-
this._highlightEffect.of({
|
|
689
|
+
this._highlightEffect.of({
|
|
690
|
+
matches: this.matches,
|
|
691
|
+
currentMatch: this._current
|
|
692
|
+
})
|
|
585
693
|
];
|
|
694
|
+
|
|
586
695
|
if (!this._cm!.state.field(this._highlightField, false)) {
|
|
587
696
|
effects.push(StateEffect.appendConfig.of([this._highlightField]));
|
|
697
|
+
// set cursor on active match when editor gets focused
|
|
698
|
+
const focusExtension = EditorView.domEventHandlers({
|
|
699
|
+
focus: () => {
|
|
700
|
+
this._selectCurrentMatch();
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
effects.push(StateEffect.appendConfig.of([focusExtension]));
|
|
588
704
|
}
|
|
589
705
|
this._cm!.editor.dispatch({ effects });
|
|
590
706
|
}
|
|
591
707
|
|
|
592
|
-
private _findNext(reverse: boolean): number | null {
|
|
708
|
+
private _findNext(reverse: boolean, fromCursor = false): number | null {
|
|
593
709
|
if (this._matches.length === 0) {
|
|
594
710
|
// No-op
|
|
595
711
|
return null;
|
|
596
712
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
// the search always proceeds from the 'anchor' position, which is at the 'from'.
|
|
608
|
-
|
|
609
|
-
const cursor = this._cm!.state.selection.main;
|
|
610
|
-
let lastPosition = reverse ? cursor.anchor : cursor.head;
|
|
713
|
+
|
|
714
|
+
let lastPosition = 0;
|
|
715
|
+
if (this._cm!.hasFocus() || fromCursor) {
|
|
716
|
+
const cursor = this._cm!.state.selection.main;
|
|
717
|
+
lastPosition = reverse ? cursor.anchor : cursor.head;
|
|
718
|
+
} else if (this._current) {
|
|
719
|
+
lastPosition = reverse
|
|
720
|
+
? this._current.position
|
|
721
|
+
: this._current.position + this._current.text.length;
|
|
722
|
+
}
|
|
611
723
|
if (lastPosition === 0 && reverse && this.currentIndex === null) {
|
|
612
724
|
// The default position is (0, 0) but we want to start from the end in that case
|
|
613
725
|
lastPosition = this._cm!.doc.length;
|
|
@@ -641,8 +753,9 @@ export class CodeMirrorSearchHighlighter {
|
|
|
641
753
|
private _cm: CodeMirrorEditor | null;
|
|
642
754
|
private _currentIndex: number | null;
|
|
643
755
|
private _matches: ISearchMatch[];
|
|
644
|
-
private _highlightEffect: StateEffectType<
|
|
756
|
+
private _highlightEffect: StateEffectType<IEffectValue>;
|
|
645
757
|
private _highlightMark: Decoration;
|
|
758
|
+
private _currentMark: Decoration;
|
|
646
759
|
private _highlightField: StateField<DecorationSet>;
|
|
647
760
|
}
|
|
648
761
|
|
package/style/base.css
CHANGED
|
@@ -63,10 +63,22 @@
|
|
|
63
63
|
color: var(--jp-search-unselected-match-color);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
.cm-searching::selection,
|
|
67
|
-
.cm-searching span::selection {
|
|
68
|
-
background-color: var(--jp-search-
|
|
69
|
-
color: var(--jp-search-
|
|
66
|
+
.cm-content .cm-searching::selection,
|
|
67
|
+
.cm-content .cm-searching span::selection {
|
|
68
|
+
background-color: var(--jp-search-unselected-match-background-color);
|
|
69
|
+
color: var(--jp-search-unselected-match-color);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.jp-current-match .cm-searching,
|
|
73
|
+
.jp-current-match .cm-searching span {
|
|
74
|
+
background-color: var(--jp-search-selected-match-background-color);
|
|
75
|
+
color: var(--jp-search-selected-match-color);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.cm-content .jp-current-match .cm-searching::selection,
|
|
79
|
+
.cm-content .jp-current-match .cm-searching span::selection {
|
|
80
|
+
background-color: var(--jp-search-selected-match-background-color);
|
|
81
|
+
color: var(--jp-search-selected-match-color);
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
.cm-trailingspace {
|