-
Notifications
You must be signed in to change notification settings - Fork 27.9k
/
findSectionHeaders.ts
120 lines (110 loc) · 3.98 KB
/
findSectionHeaders.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
108
109
110
111
112
113
114
115
116
117
118
119
120
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IRange } from 'vs/editor/common/core/range';
import { FoldingRules } from 'vs/editor/common/languages/languageConfiguration';
export interface ISectionHeaderFinderTarget {
getLineCount(): number;
getLineContent(lineNumber: number): string;
}
export interface FindSectionHeaderOptions {
foldingRules?: FoldingRules;
findRegionSectionHeaders: boolean;
findMarkSectionHeaders: boolean;
}
export interface SectionHeader {
/**
* The location of the header text in the text model.
*/
range: IRange;
/**
* The section header text.
*/
text: string;
/**
* Whether the section header includes a separator line.
*/
hasSeparatorLine: boolean;
/**
* This section should be omitted before rendering if it's not in a comment.
*/
shouldBeInComments: boolean;
}
const markRegex = /\bMARK:\s*(.*)$/d;
const trimDashesRegex = /^-+|-+$/g;
/**
* Find section headers in the model.
*
* @param model the text model to search in
* @param options options to search with
* @returns an array of section headers
*/
export function findSectionHeaders(model: ISectionHeaderFinderTarget, options: FindSectionHeaderOptions): SectionHeader[] {
let headers: SectionHeader[] = [];
if (options.findRegionSectionHeaders && options.foldingRules?.markers) {
const regionHeaders = collectRegionHeaders(model, options);
headers = headers.concat(regionHeaders);
}
if (options.findMarkSectionHeaders) {
const markHeaders = collectMarkHeaders(model);
headers = headers.concat(markHeaders);
}
return headers;
}
function collectRegionHeaders(model: ISectionHeaderFinderTarget, options: FindSectionHeaderOptions): SectionHeader[] {
const regionHeaders: SectionHeader[] = [];
const endLineNumber = model.getLineCount();
for (let lineNumber = 1; lineNumber <= endLineNumber; lineNumber++) {
const lineContent = model.getLineContent(lineNumber);
const match = lineContent.match(options.foldingRules!.markers!.start);
if (match) {
const range = { startLineNumber: lineNumber, startColumn: match[0].length + 1, endLineNumber: lineNumber, endColumn: lineContent.length + 1 };
if (range.endColumn > range.startColumn) {
const sectionHeader = {
range,
...getHeaderText(lineContent.substring(match[0].length)),
shouldBeInComments: false
};
if (sectionHeader.text || sectionHeader.hasSeparatorLine) {
regionHeaders.push(sectionHeader);
}
}
}
}
return regionHeaders;
}
function collectMarkHeaders(model: ISectionHeaderFinderTarget): SectionHeader[] {
const markHeaders: SectionHeader[] = [];
const endLineNumber = model.getLineCount();
for (let lineNumber = 1; lineNumber <= endLineNumber; lineNumber++) {
const lineContent = model.getLineContent(lineNumber);
addMarkHeaderIfFound(lineContent, lineNumber, markHeaders);
}
return markHeaders;
}
function addMarkHeaderIfFound(lineContent: string, lineNumber: number, sectionHeaders: SectionHeader[]) {
markRegex.lastIndex = 0;
const match = markRegex.exec(lineContent);
if (match) {
const column = match.indices![1][0] + 1;
const endColumn = match.indices![1][1] + 1;
const range = { startLineNumber: lineNumber, startColumn: column, endLineNumber: lineNumber, endColumn: endColumn };
if (range.endColumn > range.startColumn) {
const sectionHeader = {
range,
...getHeaderText(match[1]),
shouldBeInComments: true
};
if (sectionHeader.text || sectionHeader.hasSeparatorLine) {
sectionHeaders.push(sectionHeader);
}
}
}
}
function getHeaderText(text: string): { text: string; hasSeparatorLine: boolean } {
text = text.trim();
const hasSeparatorLine = text.startsWith('-');
text = text.replace(trimDashesRegex, '');
return { text, hasSeparatorLine };
}