forked from microsoft/vscode-textmate
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.ts
145 lines (121 loc) · 3.78 KB
/
main.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
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
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
'use strict';
import {SyncRegistry as SyncRegistry} from './registry';
import {readGrammar, readGrammarSync} from './grammarReader';
import {IRawGrammar} from './types';
interface IBarrier {
(): void;
}
let DEFAULT_LOCATOR:IGrammarLocator = {
getFilePath: (scopeName:string) => null,
getInjections: (scopeName:string) => null
};
/**
* A registry helper that can locate grammar file paths given scope names.
*/
export interface IGrammarLocator {
getFilePath(scopeName:string): string;
getInjections?(scopeName:string): string[];
}
/**
* The registry that will hold all grammars.
*/
export class Registry {
private _locator: IGrammarLocator;
private _syncRegistry: SyncRegistry;
constructor(locator:IGrammarLocator = DEFAULT_LOCATOR) {
this._locator = locator;
this._syncRegistry = new SyncRegistry();
}
/**
* Load the grammar for `scopeName` and all referenced included grammars asynchronously.
*/
public loadGrammar(initialScopeName:string, callback:(err:any, grammar:IGrammar)=>void): void {
let remainingScopeNames = [ initialScopeName ];
let seenScopeNames : {[name:string]: boolean;} = {};
seenScopeNames[initialScopeName] = true;
while (remainingScopeNames.length > 0) {
let scopeName = remainingScopeNames.shift();
if (this._syncRegistry.lookup(scopeName)) {
continue;
}
let filePath = this._locator.getFilePath(scopeName);
if (!filePath) {
if (scopeName === initialScopeName) {
callback(new Error('Unknown location for grammar <' + initialScopeName + '>'), null);
return;
}
continue;
}
try {
let grammar = readGrammarSync(filePath);
let injections = (typeof this._locator.getInjections === 'function') && this._locator.getInjections(scopeName);
let deps = this._syncRegistry.addGrammar(grammar, injections);
deps.forEach((dep) => {
if (!seenScopeNames[dep]) {
seenScopeNames[dep] = true;
remainingScopeNames.push(dep);
}
});
} catch(err) {
if (scopeName === initialScopeName) {
callback(new Error('Unknown location for grammar <' + initialScopeName + '>'), null);
return;
}
}
}
callback(null, this.grammarForScopeName(initialScopeName));
}
/**
* Load the grammar at `path` synchronously.
*/
public loadGrammarFromPathSync(path:string): IGrammar {
let rawGrammar = readGrammarSync(path);
let injections = this._locator.getInjections(rawGrammar.scopeName);
this._syncRegistry.addGrammar(rawGrammar, injections);
return this.grammarForScopeName(rawGrammar.scopeName);
}
/**
* Get the grammar for `scopeName`. The grammar must first be created via `loadGrammar` or `loadGrammarFromPathSync`.
*/
public grammarForScopeName(scopeName:string): IGrammar {
return this._syncRegistry.grammarForScopeName(scopeName);
}
}
export interface IGrammarInfo {
fileTypes: string[];
name: string;
scopeName: string;
firstLineMatch: string;
}
/**
* A grammar
*/
export interface IGrammar {
/**
* Tokenize `lineText` using previous line state `prevState`.
*/
tokenizeLine(lineText: string, prevState: StackElement): ITokenizeLineResult;
}
export interface ITokenizeLineResult {
tokens: IToken[];
/**
* The `prevState` to be passed on to the next line tokenization.
*/
ruleStack: StackElement;
}
export interface IToken {
startIndex: number;
endIndex: number;
scopes: string[];
}
/**
* **IMPORTANT** - Immutable!
*/
export interface StackElement {
_parent: StackElement;
_stackElementBrand: void;
equals(other:StackElement): boolean;
}