CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/jupyter/util/find.ts
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/*
7
This code is inspired by the BSD licensed Jupyter code, in order to maintain
8
a compatible interpretation of how things work:
9
10
notebook/notebook/static/notebook/js/searchandreplace.js
11
*/
12
13
/*
14
Escape a Regular expression to act as a pure search string,
15
though it will still have the case sensitivity options and all the benefits.
16
*/
17
function escape_regexp(string: string) {
18
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
19
}
20
21
function construct_regexp(
22
string: string,
23
flags: string,
24
is_regexp: false
25
): RegExp;
26
function construct_regexp(
27
string: RegExp,
28
flags: string,
29
is_regexp: true
30
): RegExp;
31
function construct_regexp(string, flags, is_regexp) {
32
// return a Pseudo RegExp object that acts
33
// either as a plain RegExp Object, or as a pure string matching.
34
if (is_regexp) {
35
return new RegExp(string, flags);
36
} else {
37
return new RegExp(escape_regexp(string), flags);
38
}
39
}
40
41
/*
42
Find all occurrences of `pattern` in `string`, match in a `case_sensitive` manner.
43
44
Return {matches:[...], abort:abort, error:error}
45
matches = list of matches {start:start, stop:stop} indexes in the string.
46
abort = abort Boolean, if more that 100 matches and the matches were aborted.
47
error = in case of problems compling regular expression
48
*/
49
export function find_matches(
50
pattern: string | RegExp,
51
string: string,
52
is_case_sensitive = false,
53
is_regexp = false,
54
max_matches = 100
55
): {
56
matches?: Array<{ start: number; stop: number }>;
57
abort?: boolean;
58
error?: string;
59
} {
60
let flags = "g";
61
if (!is_case_sensitive) {
62
flags += "i";
63
}
64
try {
65
pattern = construct_regexp(pattern as any, flags, is_regexp as any);
66
} catch (error) {
67
return { error: `${error}` };
68
}
69
70
const matches: any = [];
71
let match: any = undefined;
72
let escape_hatch = 0;
73
let abort = false;
74
while ((match = (pattern as any).exec(string)) != null) {
75
match = { start: match.index, stop: match.index + match[0].length };
76
if (match.stop === match.start) {
77
// e.g., an empty search
78
return { matches: [] };
79
}
80
matches.push(match);
81
escape_hatch++;
82
if (escape_hatch >= max_matches) {
83
abort = true;
84
break;
85
}
86
}
87
88
const x: any = { matches };
89
if (abort) {
90
x.abort = abort;
91
}
92
return x;
93
}
94
95