forked from banga/git-split-diffs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwrapSpannedStringByWord.ts
More file actions
92 lines (81 loc) · 2.53 KB
/
Copy pathwrapSpannedStringByWord.ts
File metadata and controls
92 lines (81 loc) · 2.53 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
import { SpannedString } from './SpannedString';
const SPACE_REGEX = /\s/;
function getLineBreaksForString(string: string, width: number): number[] {
const lineBreaks: number[] = [];
let budget = width;
let curLineEnd = 0;
function flushLine() {
lineBreaks.push(curLineEnd);
budget = width;
}
function pushWord(startIndex: number, endIndex: number) {
const wordLength = endIndex - startIndex;
// word can fit on current line
if (wordLength <= budget) {
curLineEnd = endIndex;
budget -= wordLength;
return;
}
// word can fit in the new line, so start a new one
if (wordLength <= width) {
flushLine();
curLineEnd = endIndex;
budget -= wordLength;
return;
}
// word is too long to fit in any line, so lets break it and push each
// part
while (startIndex < endIndex) {
if (budget === 0) {
flushLine();
}
let remainingLengthInLine = Math.min(budget, endIndex - startIndex);
curLineEnd += remainingLengthInLine;
startIndex += remainingLengthInLine;
flushLine();
}
}
let prevIndex = 0;
let curIndex = 1;
let prevIsSpace = SPACE_REGEX.test(string[prevIndex]);
// Add one word at a time
while (curIndex < string.length) {
const isSpace = SPACE_REGEX.test(string[curIndex]);
if (isSpace) {
pushWord(prevIndex, curIndex);
prevIndex = curIndex;
} else if (prevIsSpace) {
pushWord(prevIndex, curIndex);
prevIndex = curIndex;
}
prevIsSpace = isSpace;
curIndex++;
}
if (prevIndex < curIndex) {
pushWord(prevIndex, curIndex);
}
if (budget < width) {
flushLine();
}
return lineBreaks;
}
export function* wrapSpannedStringByWord<T>(
spannedString: SpannedString<T>,
width: number
): Iterable<SpannedString<T>> {
// Short circuit if no wrapping is required
const string = spannedString.getString();
if (string.length < width) {
yield spannedString;
return;
}
const lineBreaks = getLineBreaksForString(string, width);
let prevLineBreak = 0;
for (const lineBreak of lineBreaks) {
yield spannedString.slice(prevLineBreak, lineBreak);
prevLineBreak = lineBreak;
}
if (prevLineBreak < string.length - 1) {
yield spannedString.slice(prevLineBreak);
}
}