forked from paradoxuum/centurion
-
Notifications
You must be signed in to change notification settings - Fork 0
/
string.ts
107 lines (93 loc) · 2.6 KB
/
string.ts
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
function charCode(n: string) {
return utf8.char(tonumber(n, 16) as number);
}
function parseEscapeSequences(text: string): string {
return text
.gsub("\\(.)", {
t: "\t",
n: "\n",
})[0]
.gsub("\\u(%x%x%x%x)", charCode)[0]
.gsub("\\x(%x%x)", charCode)[0];
}
function encodeControlChars(text: string) {
return text
.gsub("\\\\", "___!CMDR_ESCAPE!___")[0]
.gsub('\\"', "___!CMDR_QUOTE!___")[0]
.gsub("\\'", "___!CMDR_SQUOTE!___")[0]
.gsub("\\\n", "___!CMDR_NL!___")[0];
}
function decodeControlChars(text: string) {
return text
.gsub("___!CMDR_ESCAPE!___", "\\")[0]
.gsub("___!CMDR_QUOTE!___", '"')[0]
.gsub("___!CMDR_NL!___", "\n")[0];
}
const START_QUOTE_PATTERN = `^(['"])`;
const END_QUOTE_PATTERN = `(['"])$`;
// eslint-disable-next-line no-useless-escape
const ESCAPE_PATTERN = `(\*)['"]$`;
/**
* Splits a string by space and takes into account quoted sentences,
* which will be treated as a single part instead of being split.
*
* @see https://github.com/evaera/Cmdr/blob/e3180638849a8615bb982bb74f970bf64435da63/Cmdr/Shared/Util.lua
* @param text The text to split
* @param max The max number of splits
* @returns The split string
*/
export function splitStringBySpace(
text: string,
max: number = math.huge,
): string[] {
const resultText = encodeControlChars(text);
const t: string[] = [];
let buf: string | undefined;
let quoted: string | undefined;
for (let [str] of resultText.gmatch("[^ ]+")) {
str = parseEscapeSequences(str as string);
const startQuote = str.match(START_QUOTE_PATTERN)[0] as string;
const endQuote = str.match(END_QUOTE_PATTERN)[0] as string;
const escaped = str.match(ESCAPE_PATTERN)[0] as string;
if (
startQuote !== undefined &&
quoted === undefined &&
endQuote === undefined
) {
[buf, quoted] = [str, startQuote];
} else if (
buf !== undefined &&
endQuote === quoted &&
escaped.size() % 2 === 0
) {
[str, buf, quoted] = [`${buf} ${str}`, undefined, undefined];
} else if (buf !== undefined) {
buf = `${buf} ${str}`;
}
if (buf !== undefined) {
continue;
}
const result = decodeControlChars(
str.gsub(START_QUOTE_PATTERN, "")[0].gsub(END_QUOTE_PATTERN, "")[0],
);
if (t.size() > max) {
t[t.size() - 1] = result;
} else {
t.push(result);
}
}
if (buf !== undefined) {
if (t.size() > max) {
t[t.size() - 1] = decodeControlChars(buf);
} else {
t.push(decodeControlChars(buf));
}
}
return t;
}
export function endsWithSpace(text: string) {
return text.size() > 0 && text.match("%s$").size() > 0;
}
export function formatPartsAsPath(textParts: string[]) {
return textParts.join("/");
}