forked from irinazheltisheva/vscode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwordHelper.ts
More file actions
136 lines (115 loc) · 3.81 KB
/
Copy pathwordHelper.ts
File metadata and controls
136 lines (115 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IWordAtPosition } from 'vs/editor/common/model';
export const USUAL_WORD_SEPARATORS = '`~!@#$%^&*()-=+[{]}\\|;:\'",.<>/?';
/**
* Create a word definition regular expression based on default word separators.
* Optionally provide allowed separators that should be included in words.
*
* The default would look like this:
* /(-?\d*\.\d\w*)|([^\`\~\!\@\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g
*/
function createWordRegExp(allowInWords: string = ''): RegExp {
let source = '(-?\\d*\\.\\d\\w*)|([^';
for (const sep of USUAL_WORD_SEPARATORS) {
if (allowInWords.indexOf(sep) >= 0) {
continue;
}
source += '\\' + sep;
}
source += '\\s]+)';
return new RegExp(source, 'g');
}
// catches numbers (including floating numbers) in the first group, and alphanum in the second
export const DEFAULT_WORD_REGEXP = createWordRegExp();
export function ensureValidWordDefinition(wordDefinition?: RegExp | null): RegExp {
let result: RegExp = DEFAULT_WORD_REGEXP;
if (wordDefinition && (wordDefinition instanceof RegExp)) {
if (!wordDefinition.global) {
let flags = 'g';
if (wordDefinition.ignoreCase) {
flags += 'i';
}
if (wordDefinition.multiline) {
flags += 'm';
}
if ((wordDefinition as any).unicode) {
flags += 'u';
}
result = new RegExp(wordDefinition.source, flags);
} else {
result = wordDefinition;
}
}
result.lastIndex = 0;
return result;
}
const _defaultConfig = {
maxLen: 1000,
windowSize: 15,
timeBudget: 150
};
export function getWordAtText(column: number, wordDefinition: RegExp, text: string, textOffset: number, config = _defaultConfig): IWordAtPosition | null {
if (text.length > config.maxLen) {
// don't throw strings that long at the regexp
// but use a sub-string in which a word must occur
let start = column - config.maxLen / 2;
if (start < 0) {
textOffset += column;
start = 0;
} else {
textOffset += start;
}
text = text.substring(start, column + config.maxLen / 2);
return getWordAtText(column, wordDefinition, text, textOffset, config);
}
const t1 = Date.now();
const pos = column - 1 - textOffset;
let prevRegexIndex = -1;
let match: RegExpMatchArray | null = null;
for (let i = 1; ; i++) {
// check time budget
if (Date.now() - t1 >= config.timeBudget) {
// break;
}
// reset the index at which the regexp should start matching, also know where it
// should stop so that subsequent search don't repeat previous searches
const regexIndex = pos - config.windowSize * i;
wordDefinition.lastIndex = Math.max(0, regexIndex);
const thisMatch = _findRegexMatchEnclosingPosition(wordDefinition, text, pos, prevRegexIndex);
if (!thisMatch && match) {
// stop: we have something
break;
}
match = thisMatch;
// stop: searched at start
if (regexIndex <= 0) {
break;
}
prevRegexIndex = regexIndex;
}
if (match) {
let result = {
word: match[0],
startColumn: textOffset + 1 + match.index!,
endColumn: textOffset + 1 + match.index! + match[0].length
};
wordDefinition.lastIndex = 0;
return result;
}
return null;
}
function _findRegexMatchEnclosingPosition(wordDefinition: RegExp, text: string, pos: number, stopPos: number): RegExpMatchArray | null {
let match: RegExpMatchArray | null;
while (match = wordDefinition.exec(text)) {
const matchIndex = match.index || 0;
if (matchIndex <= pos && wordDefinition.lastIndex >= pos) {
return match;
} else if (stopPos > 0 && matchIndex > stopPos) {
return null;
}
}
return null;
}