Skip to content

Commit db0b856

Browse files
committed
simplify ts mode to not use the parser
It is sure a regression, but the parser was quite consuming and made editing large file a pain
1 parent 2271e53 commit db0b856

File tree

1 file changed

+139
-67
lines changed

1 file changed

+139
-67
lines changed

src/main/mode.ts

Lines changed: 139 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -14,53 +14,34 @@
1414

1515
'use strict';
1616

17-
// TODO If we could not depends of TypeScript here, or at least extract just the part we are interested in
18-
// We could avoid bundling the entire TypeScript Service with use
19-
// see : https://github.com/fdecampredon/brackets-typescript/issues/13
2017

21-
22-
declare var require: any;
2318
import ts = require('typescript');
24-
import indenter = require('./smartIndenter');
25-
26-
2719

28-
interface Token {
20+
type Token = {
2921
string: string;
3022
classification: ts.TokenClass;
3123
length: number;
3224
position: number;
3325
}
3426

27+
type BracketsStackItem = {
28+
indent: number ; brackets: string[]
29+
}
3530

3631
interface LineDescriptor {
3732
tokenMap: { [position: number]: Token };
3833
eolState: ts.EndOfLineState;
39-
text: string;
34+
indent: number;
35+
nextLineIndent: number;
36+
bracketsStack: BracketsStackItem[]
4037
}
4138

42-
function createLineDescriptor() {
43-
return {
44-
tokenMap: {},
45-
eolState: ts.EndOfLineState.Start,
46-
text: ''
47-
}
48-
}
4939

50-
function cloneLineDescriptor(lineDescriptor: LineDescriptor): LineDescriptor {
51-
return {
52-
tokenMap: lineDescriptor.tokenMap,
53-
eolState: lineDescriptor.eolState,
54-
text: lineDescriptor.text
55-
}
40+
function last<T>(arr: T[]) {
41+
return arr[arr.length -1];
5642
}
5743

58-
59-
60-
61-
var classifier: ts.Classifier = ts.createClassifier({
62-
log: () => void 0
63-
});
44+
var classifier: ts.Classifier = ts.createClassifier({ log: () => void 0 });
6445

6546
function getClassificationsForLine(text: string, eolState: ts.EndOfLineState ) {
6647
var classificationResult = classifier.getClassificationsForLine(text, eolState),
@@ -137,28 +118,111 @@ function getStyleForToken(token: Token, textBefore: string): string {
137118
}
138119
}
139120

140-
function initializeLineDescriptor(lineDescriptor: LineDescriptor, text: string) {
141-
var classificationResult = getClassificationsForLine(text, lineDescriptor.eolState),
142-
tokens = classificationResult.tokens;
143121

144-
if (lineDescriptor.text) {
145-
lineDescriptor.text += '\n';
122+
var openingBrackets = ['{', '(', '[', '<'];
123+
var closingBrackets = ['}', ')', ']', '>'];
124+
125+
function isOpening(bracket: string) {
126+
return openingBrackets.indexOf(bracket) !== -1;
127+
}
128+
129+
function isClosing(bracket: string) {
130+
return closingBrackets.indexOf(bracket) !== -1;
131+
}
132+
133+
134+
function isPair(opening: string, closing: string) {
135+
return openingBrackets.indexOf(opening) === closingBrackets.indexOf(closing);
136+
}
137+
138+
139+
function getLineDescriptorInfo(text: string, eolState: ts.EndOfLineState, indent: number, bracketsStack: BracketsStackItem[]) {
140+
bracketsStack = bracketsStack.map(item => ({
141+
indent: item.indent,
142+
brackets: item.brackets.slice()
143+
}));
144+
145+
var classificationResult = getClassificationsForLine(text, eolState);
146+
var tokens = classificationResult.tokens;
147+
var tokenMap: { [position: number]: Token } = {};
148+
149+
var openedBrackets: string[] = [];
150+
var closedBrackets: string[] = []
151+
152+
function openBracket(openedBracket: string) {
153+
openedBrackets.push(openedBracket);
146154
}
147-
lineDescriptor.text += text;
148-
lineDescriptor.eolState = classificationResult.eolState;
149-
lineDescriptor.tokenMap = {};
150155

151-
for (var i = 0, l = tokens.length; i < l; i++) {
152-
lineDescriptor.tokenMap[tokens[i].position] = tokens[i];
156+
function closeBracket(closedBracket: string) {
157+
var openedBracket = last(openedBrackets)
158+
if (openedBracket) {
159+
if (isPair(openedBracket, closedBracket)) {
160+
openedBrackets.pop();
161+
}
162+
} else {
163+
closedBrackets.push(closedBracket)
164+
}
153165
}
154-
}
155-
function setParent(parent: ts.Node) {
156-
parent.getChildren().forEach(node => {
157-
if (!node.parent) {
158-
node.parent = parent;
166+
167+
168+
for (var i = 0, l = tokens.length; i < l; i++) {
169+
var token = tokens[i];
170+
tokenMap[token.position] = token;
171+
if (token.classification === ts.TokenClass.Punctuation) {
172+
if (isClosing(token.string)) {
173+
closeBracket(token.string);
174+
} else if (isOpening(token.string)) {
175+
openBracket(token.string);
176+
}
159177
}
160-
setParent(node);
161-
})
178+
}
179+
180+
181+
182+
if(closedBrackets.length) {
183+
var newStack: string[][] = [];
184+
for (var i = bracketsStack.length -1; i >=0; i--) {
185+
var item = bracketsStack[i];
186+
var brackets = item.brackets;
187+
188+
var hasPair = false;
189+
while (
190+
isPair(last(brackets), closedBrackets[0]) &&
191+
brackets.length && item.brackets.length
192+
) {
193+
brackets.pop();
194+
closedBrackets.shift();
195+
hasPair = true;
196+
}
197+
198+
if (hasPair) {
199+
indent = item.indent;
200+
}
201+
202+
if (!brackets.length) {
203+
bracketsStack.pop();
204+
} else {
205+
// in this case we had closing token that are not pair with our openingStack
206+
// error
207+
break;
208+
}
209+
}
210+
}
211+
212+
if (openedBrackets.length) {
213+
bracketsStack.push({
214+
indent: indent,
215+
brackets: openedBrackets
216+
});
217+
}
218+
219+
return {
220+
eolState: classificationResult.eolState,
221+
tokenMap: tokenMap,
222+
indent: indent,
223+
bracketsStack: bracketsStack,
224+
hasOpening: !!openedBrackets.length
225+
}
162226
}
163227

164228
function createTypeScriptMode(options: CodeMirror.EditorConfiguration, spec: any): CodeMirror.CodeMirrorMode<any> {
@@ -168,17 +232,35 @@ function createTypeScriptMode(options: CodeMirror.EditorConfiguration, spec: any
168232
blockCommentEnd: '*/',
169233
electricChars: ':{}[]()',
170234

171-
startState() {
172-
return createLineDescriptor();
235+
startState(): LineDescriptor {
236+
return {
237+
tokenMap: {},
238+
eolState: ts.EndOfLineState.Start,
239+
indent: 0,
240+
nextLineIndent: 0,
241+
bracketsStack: []
242+
};
173243
},
174244

175245
copyState(lineDescriptor: LineDescriptor) {
176-
return cloneLineDescriptor(lineDescriptor);
246+
return {
247+
tokenMap: lineDescriptor.tokenMap,
248+
eolState: lineDescriptor.eolState,
249+
indent: lineDescriptor.indent,
250+
nextLineIndent: lineDescriptor.nextLineIndent,
251+
bracketsStack: lineDescriptor.bracketsStack
252+
}
177253
},
178254

179255
token(stream: CodeMirror.CodeMirrorStream, lineDescriptor: LineDescriptor) {
180256
if (stream.sol()) {
181-
initializeLineDescriptor(lineDescriptor, stream.string);
257+
var info = getLineDescriptorInfo(stream.string, lineDescriptor.eolState, lineDescriptor.nextLineIndent, lineDescriptor.bracketsStack);
258+
259+
lineDescriptor.eolState = info.eolState;
260+
lineDescriptor.tokenMap = info.tokenMap;
261+
lineDescriptor.bracketsStack = info.bracketsStack;
262+
lineDescriptor.indent = info.indent;
263+
lineDescriptor.nextLineIndent = info.hasOpening ? info.indent + 1 : info.indent;
182264
}
183265

184266
var token = lineDescriptor.tokenMap[stream.pos];
@@ -201,25 +283,15 @@ function createTypeScriptMode(options: CodeMirror.EditorConfiguration, spec: any
201283
if (lineDescriptor.eolState !== ts.EndOfLineState.Start) {
202284
return CodeMirror.Pass;
203285
}
204-
var text = lineDescriptor.text + '\n' + (textAfter || 'fakeIndent');
205-
var position = textAfter ? text.length: text.length - 9;
206-
var sourceFile = ts.createSourceFile(Math.random()+ '.ts', text, ts.ScriptTarget.Latest, Math.random() + '');
207-
setParent(sourceFile);
208-
var indent = indenter.getIndentation(position, sourceFile, {
209-
IndentSize: options.indentUnit,
210-
TabSize: options.tabSize,
211-
NewLineCharacter: '\n',
212-
ConvertTabsToSpaces: !options.indentWithTabs
213-
});
214-
215-
if (indent === null) {
216-
return CodeMirror.Pass;
217-
}
218-
return indent;
286+
287+
var indent = lineDescriptor.nextLineIndent;
288+
if (textAfter) {
289+
indent = getLineDescriptorInfo(textAfter, lineDescriptor.eolState, lineDescriptor.nextLineIndent, lineDescriptor.bracketsStack).indent;
290+
}
291+
292+
return indent * options.indentUnit
219293
}
220294
}
221-
222-
223295
}
224296

225297
export = createTypeScriptMode;

0 commit comments

Comments
 (0)