forked from microsoft/TypeScript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindentation.ts
More file actions
154 lines (125 loc) · 6.54 KB
/
Copy pathindentation.ts
File metadata and controls
154 lines (125 loc) · 6.54 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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
module TypeScript.Indentation {
export function columnForEndOfTokenAtPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number {
var token = findToken(syntaxTree.sourceUnit(), position);
return columnForStartOfTokenAtPosition(syntaxTree, position, options) + width(token);
}
export function columnForStartOfTokenAtPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number {
var token = findToken(syntaxTree.sourceUnit(), position);
// Walk backward from this token until we find the first token in the line. For each token
// we see (that is not the first tokem in line), push the entirety of the text into the text
// array. Then, for the first token, add its text (without its leading trivia) to the text
// array. i.e. if we have:
//
// var foo = a => bar();
//
// And we want the column for the start of 'bar', then we'll add the underlinded portions to
// the text array:
//
// var foo = a => bar();
// _
// __
// __
// ____
// ____
var firstTokenInLine = Syntax.firstTokenInLineContainingPosition(syntaxTree, token.fullStart());
var leadingTextInReverse: string[] = [];
var current = token;
while (current !== firstTokenInLine) {
current = previousToken(current);
if (current === firstTokenInLine) {
// We're at the first token in teh line.
// We don't want the leading trivia for this token. That will be taken care of in
// columnForFirstNonWhitespaceCharacterInLine. So just push the trailing trivia
// and then the token text.
leadingTextInReverse.push(current.trailingTrivia().fullText());
leadingTextInReverse.push(current.text());
}
else {
// We're at an intermediate token on the line. Just push all its text into the array.
leadingTextInReverse.push(current.fullText());
}
}
// Now, add all trivia to the start of the line on the first token in the list.
collectLeadingTriviaTextToStartOfLine(firstTokenInLine, leadingTextInReverse);
return columnForLeadingTextInReverse(leadingTextInReverse, options);
}
export function columnForStartOfFirstTokenInLineContainingPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number {
// Walk backward through the tokens until we find the first one on the line.
var firstTokenInLine = Syntax.firstTokenInLineContainingPosition(syntaxTree, position);
var leadingTextInReverse: string[] = [];
// Now, add all trivia to the start of the line on the first token in the list.
collectLeadingTriviaTextToStartOfLine(firstTokenInLine, leadingTextInReverse);
return columnForLeadingTextInReverse(leadingTextInReverse, options);
}
// Collect all the trivia that precedes this token. Stopping when we hit a newline trivia
// or a multiline comment that spans multiple lines. This is meant to be called on the first
// token in a line.
function collectLeadingTriviaTextToStartOfLine(firstTokenInLine: ISyntaxToken,
leadingTextInReverse: string[]) {
var leadingTrivia = firstTokenInLine.leadingTrivia();
for (var i = leadingTrivia.count() - 1; i >= 0; i--) {
var trivia = leadingTrivia.syntaxTriviaAt(i);
if (trivia.kind() === SyntaxKind.NewLineTrivia) {
break;
}
if (trivia.kind() === SyntaxKind.MultiLineCommentTrivia) {
var lineSegments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia);
leadingTextInReverse.push(ArrayUtilities.last(lineSegments));
if (lineSegments.length > 0) {
// This multiline comment actually spanned multiple lines. So we're done.
break;
}
// It was only on a single line, so keep on going.
}
leadingTextInReverse.push(trivia.fullText());
}
}
function columnForLeadingTextInReverse(leadingTextInReverse: string[],
options: FormattingOptions): number {
var column = 0;
// walk backwards. This means we're actually walking forward from column 0 to the start of
// the token.
for (var i = leadingTextInReverse.length - 1; i >= 0; i--) {
var text = leadingTextInReverse[i];
column = columnForPositionInStringWorker(text, text.length, column, options);
}
return column;
}
// Returns the column that this input string ends at (assuming it starts at column 0).
export function columnForPositionInString(input: string, position: number, options: FormattingOptions): number {
return columnForPositionInStringWorker(input, position, 0, options);
}
function columnForPositionInStringWorker(input: string, position: number, startColumn: number, options: FormattingOptions): number {
var column = startColumn;
var spacesPerTab = options.spacesPerTab;
for (var j = 0; j < position; j++) {
var ch = input.charCodeAt(j);
if (ch === CharacterCodes.tab) {
column += spacesPerTab - column % spacesPerTab;
}
else {
column++;
}
}
return column;
}
export function indentationString(column: number, options: FormattingOptions): string {
var numberOfTabs = 0;
var numberOfSpaces = Math.max(0, column);
if (options.useTabs) {
numberOfTabs = Math.floor(column / options.spacesPerTab);
numberOfSpaces -= numberOfTabs * options.spacesPerTab;
}
return StringUtilities.repeat('\t', numberOfTabs) +
StringUtilities.repeat(' ', numberOfSpaces);
}
export function firstNonWhitespacePosition(value: string): number {
for (var i = 0; i < value.length; i++) {
var ch = value.charCodeAt(i);
if (!CharacterInfo.isWhitespace(ch)) {
return i;
}
}
return value.length;
}
}