mirror of
https://github.com/microsoft/monaco-editor.git
synced 2025-12-22 07:00:11 +01:00
Initial version
This commit is contained in:
parent
a818bfffee
commit
331acc5fef
26 changed files with 59386 additions and 2 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/node_modules/
|
||||
/out/
|
||||
/release/
|
||||
8
.npmignore
Normal file
8
.npmignore
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/.vscode/
|
||||
/lib/
|
||||
/out/
|
||||
/src/
|
||||
/test/
|
||||
/gulpfile.js
|
||||
/tsconfig.json
|
||||
/.npmignore
|
||||
9
.vscode/settings.json
vendored
Normal file
9
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"search.exclude": {
|
||||
"**/node_modules": true,
|
||||
"**/release": true,
|
||||
"**/out": true
|
||||
}
|
||||
}
|
||||
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
14
README.md
14
README.md
|
|
@ -1,2 +1,12 @@
|
|||
# monaco-typescript
|
||||
TypeScript/JavaScript language support for the Monaco Editor
|
||||
# Monaco TypeScript
|
||||
|
||||
TypeScript and JavaScript language support for the Monaco Editor.
|
||||
|
||||

|
||||
|
||||
## Installing
|
||||
|
||||
This npm module is bundled and distributed in the [monaco-editor](https://www.npmjs.com/package/monaco-editor) npm module.
|
||||
|
||||
## License
|
||||
[MIT](https://github.com/Microsoft/monaco-typescript/blob/master/LICENSE.md)
|
||||
|
|
|
|||
273
gulpfile.js
Normal file
273
gulpfile.js
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
var gulp = require('gulp');
|
||||
var tsb = require('gulp-tsb');
|
||||
var assign = require('object-assign');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var merge = require('merge-stream');
|
||||
var rjs = require('gulp-requirejs');
|
||||
var uglify = require('gulp-uglify');
|
||||
var rimraf = require('rimraf');
|
||||
var es = require('event-stream');
|
||||
|
||||
var TYPESCRIPT_LIB_SOURCE = path.join(__dirname, 'node_modules', 'typescript', 'lib');
|
||||
var TYPESCRIPT_LIB_DESTINATION = path.join(__dirname, 'lib');
|
||||
|
||||
gulp.task('clean-release', function(cb) { rimraf('release', { maxBusyTries: 1 }, cb); });
|
||||
gulp.task('release', ['clean-release','compile'], function() {
|
||||
|
||||
var sha1 = getGitVersion(__dirname);
|
||||
var semver = require('./package.json').version;
|
||||
var headerVersion = semver + '(' + sha1 + ')';
|
||||
|
||||
var BUNDLED_FILE_HEADER = [
|
||||
'/*!-----------------------------------------------------------------------------',
|
||||
' * Copyright (c) Microsoft Corporation. All rights reserved.',
|
||||
' * monaco-typescript version: ' + headerVersion,
|
||||
' * Released under the MIT license',
|
||||
' * https://github.com/Microsoft/monaco-typescript/blob/master/LICENSE.md',
|
||||
' *-----------------------------------------------------------------------------*/',
|
||||
''
|
||||
].join('\n');
|
||||
|
||||
function bundleOne(moduleId, exclude) {
|
||||
return rjs({
|
||||
baseUrl: '/out/',
|
||||
name: 'vs/language/typescript/' + moduleId,
|
||||
out: moduleId + '.js',
|
||||
exclude: exclude,
|
||||
paths: {
|
||||
'vs/language/typescript': __dirname + '/out'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return merge(
|
||||
bundleOne('src/monaco.contribution'),
|
||||
bundleOne('lib/typescriptServices'),
|
||||
bundleOne('src/mode', ['vs/language/typescript/lib/typescriptServices']),
|
||||
bundleOne('src/worker', ['vs/language/typescript/lib/typescriptServices'])
|
||||
)
|
||||
.pipe(uglify({
|
||||
preserveComments: 'some'
|
||||
}))
|
||||
.pipe(es.through(function(data) {
|
||||
data.contents = new Buffer(
|
||||
BUNDLED_FILE_HEADER
|
||||
+ data.contents.toString()
|
||||
);
|
||||
this.emit('data', data);
|
||||
}))
|
||||
.pipe(gulp.dest('./release/'));
|
||||
});
|
||||
|
||||
|
||||
var compilation = tsb.create(assign({ verbose: true }, require('./tsconfig.json').compilerOptions));
|
||||
|
||||
var tsSources = require('./tsconfig.json').filesGlob;
|
||||
|
||||
function compileTask() {
|
||||
return merge(
|
||||
gulp.src('lib/*.js', { base: '.' }),
|
||||
gulp.src(tsSources).pipe(compilation())
|
||||
)
|
||||
.pipe(gulp.dest('out'));
|
||||
}
|
||||
|
||||
gulp.task('clean-out', function(cb) { rimraf('out', { maxBusyTries: 1 }, cb); });
|
||||
gulp.task('compile', ['clean-out'], compileTask);
|
||||
gulp.task('compile-without-clean', compileTask);
|
||||
gulp.task('watch', ['compile'], function() {
|
||||
gulp.watch(tsSources, ['compile-without-clean']);
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Import files from TypeScript's dist
|
||||
*/
|
||||
gulp.task('import-typescript', function() {
|
||||
try {
|
||||
fs.statSync(TYPESCRIPT_LIB_DESTINATION);
|
||||
} catch (err) {
|
||||
fs.mkdirSync(TYPESCRIPT_LIB_DESTINATION);
|
||||
}
|
||||
importLibDeclarationFile('lib.d.ts');
|
||||
importLibDeclarationFile('lib.es6.d.ts');
|
||||
|
||||
var tsServices = fs.readFileSync(path.join(TYPESCRIPT_LIB_SOURCE, 'typescriptServices.js')).toString();
|
||||
tsServices +=
|
||||
`
|
||||
// MONACOCHANGE
|
||||
define([], function() { return ts; });
|
||||
// END MONACOCHANGE
|
||||
`;
|
||||
fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices.js'), tsServices);
|
||||
|
||||
var dtsServices = fs.readFileSync(path.join(TYPESCRIPT_LIB_SOURCE, 'typescriptServices.d.ts')).toString();
|
||||
dtsServices +=
|
||||
`
|
||||
// MONACOCHANGE
|
||||
export = ts;
|
||||
// END MONACOCHANGE
|
||||
`;
|
||||
fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices.d.ts'), dtsServices);
|
||||
});
|
||||
|
||||
/**
|
||||
* Import a lib*.d.ts file from TypeScript's dist
|
||||
*/
|
||||
function importLibDeclarationFile(name) {
|
||||
var dstName = name.replace(/\.d\.ts$/, '').replace(/\./g, '-') + '-ts';
|
||||
var srcPath = path.join(TYPESCRIPT_LIB_SOURCE, name);
|
||||
|
||||
var contents = fs.readFileSync(srcPath).toString();
|
||||
|
||||
var dstPath1 = path.join(TYPESCRIPT_LIB_DESTINATION, dstName + '.js');
|
||||
fs.writeFileSync(dstPath1,
|
||||
`/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// This is a generated file from ${name}
|
||||
|
||||
define([], function() { return { contents: "${escapeText(contents)}"}; });
|
||||
|
||||
`);
|
||||
|
||||
var dstPath2 = path.join(TYPESCRIPT_LIB_DESTINATION, dstName + '.d.ts');
|
||||
fs.writeFileSync(dstPath2,
|
||||
`/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export declare var contents: string;
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape text such that it can be used in a javascript string enclosed by double quotes (")
|
||||
*/
|
||||
function escapeText(text) {
|
||||
// http://www.javascriptkit.com/jsref/escapesequence.shtml
|
||||
// \b Backspace.
|
||||
// \f Form feed.
|
||||
// \n Newline.
|
||||
// \O Nul character.
|
||||
// \r Carriage return.
|
||||
// \t Horizontal tab.
|
||||
// \v Vertical tab.
|
||||
// \' Single quote or apostrophe.
|
||||
// \" Double quote.
|
||||
// \\ Backslash.
|
||||
// \ddd The Latin-1 character specified by the three octal digits between 0 and 377. ie, copyright symbol is \251.
|
||||
// \xdd The Latin-1 character specified by the two hexadecimal digits dd between 00 and FF. ie, copyright symbol is \xA9.
|
||||
// \udddd The Unicode character specified by the four hexadecimal digits dddd. ie, copyright symbol is \u00A9.
|
||||
var _backspace = '\b'.charCodeAt(0);
|
||||
var _formFeed = '\f'.charCodeAt(0);
|
||||
var _newLine = '\n'.charCodeAt(0);
|
||||
var _nullChar = 0;
|
||||
var _carriageReturn = '\r'.charCodeAt(0);
|
||||
var _tab = '\t'.charCodeAt(0);
|
||||
var _verticalTab = '\v'.charCodeAt(0);
|
||||
var _backslash = '\\'.charCodeAt(0);
|
||||
var _doubleQuote = '"'.charCodeAt(0);
|
||||
|
||||
var startPos = 0, chrCode, replaceWith = null, resultPieces = [];
|
||||
|
||||
for (var i = 0, len = text.length; i < len; i++) {
|
||||
chrCode = text.charCodeAt(i);
|
||||
switch (chrCode) {
|
||||
case _backspace:
|
||||
replaceWith = '\\b';
|
||||
break;
|
||||
case _formFeed:
|
||||
replaceWith = '\\f';
|
||||
break;
|
||||
case _newLine:
|
||||
replaceWith = '\\n';
|
||||
break;
|
||||
case _nullChar:
|
||||
replaceWith = '\\0';
|
||||
break;
|
||||
case _carriageReturn:
|
||||
replaceWith = '\\r';
|
||||
break;
|
||||
case _tab:
|
||||
replaceWith = '\\t';
|
||||
break;
|
||||
case _verticalTab:
|
||||
replaceWith = '\\v';
|
||||
break;
|
||||
case _backslash:
|
||||
replaceWith = '\\\\';
|
||||
break;
|
||||
case _doubleQuote:
|
||||
replaceWith = '\\"';
|
||||
break;
|
||||
}
|
||||
if (replaceWith !== null) {
|
||||
resultPieces.push(text.substring(startPos, i));
|
||||
resultPieces.push(replaceWith);
|
||||
startPos = i + 1;
|
||||
replaceWith = null;
|
||||
}
|
||||
}
|
||||
resultPieces.push(text.substring(startPos, len));
|
||||
return resultPieces.join('');
|
||||
}
|
||||
|
||||
function getGitVersion(repo) {
|
||||
var git = path.join(repo, '.git');
|
||||
var headPath = path.join(git, 'HEAD');
|
||||
var head;
|
||||
|
||||
try {
|
||||
head = fs.readFileSync(headPath, 'utf8').trim();
|
||||
} catch (e) {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
if (/^[0-9a-f]{40}$/i.test(head)) {
|
||||
return head;
|
||||
}
|
||||
|
||||
var refMatch = /^ref: (.*)$/.exec(head);
|
||||
|
||||
if (!refMatch) {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
var ref = refMatch[1];
|
||||
var refPath = path.join(git, ref);
|
||||
|
||||
try {
|
||||
return fs.readFileSync(refPath, 'utf8').trim();
|
||||
} catch (e) {
|
||||
// noop
|
||||
}
|
||||
|
||||
var packedRefsPath = path.join(git, 'packed-refs');
|
||||
var refsRaw;
|
||||
|
||||
try {
|
||||
refsRaw = fs.readFileSync(packedRefsPath, 'utf8').trim();
|
||||
} catch (e) {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
var refsRegex = /^([0-9a-f]{40})\s+(.+)$/gm;
|
||||
var refsMatch;
|
||||
var refs = {};
|
||||
|
||||
while (refsMatch = refsRegex.exec(refsRaw)) {
|
||||
refs[refsMatch[2]] = refsMatch[1];
|
||||
}
|
||||
|
||||
return refs[ref];
|
||||
}
|
||||
6
lib/lib-es6-ts.d.ts
vendored
Normal file
6
lib/lib-es6-ts.d.ts
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export declare var contents: string;
|
||||
9
lib/lib-es6-ts.js
Normal file
9
lib/lib-es6-ts.js
Normal file
File diff suppressed because one or more lines are too long
6
lib/lib-ts.d.ts
vendored
Normal file
6
lib/lib-ts.d.ts
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export declare var contents: string;
|
||||
9
lib/lib-ts.js
Normal file
9
lib/lib-ts.js
Normal file
File diff suppressed because one or more lines are too long
2348
lib/typescriptServices.d.ts
vendored
Normal file
2348
lib/typescriptServices.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load diff
54817
lib/typescriptServices.js
Normal file
54817
lib/typescriptServices.js
Normal file
File diff suppressed because one or more lines are too long
33
package.json
Normal file
33
package.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "monaco-typescript",
|
||||
"version": "0.1.0",
|
||||
"description": "TypeScript and JavaScript language support for Monaco Editor",
|
||||
"scripts": {
|
||||
"test": "node_modules/.bin/mocha",
|
||||
"watch": "node_modules/.bin/gulp watch",
|
||||
"prepublish": "node_modules/.bin/gulp release"
|
||||
},
|
||||
"author": "Microsoft Corporation",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/monaco-typescript"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Microsoft/monaco-typescript/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"event-stream": "^3.3.2",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-requirejs": "^0.1.3",
|
||||
"gulp-tsb": "^1.10.4",
|
||||
"gulp-uglify": "^1.5.3",
|
||||
"merge-stream": "^1.0.0",
|
||||
"mocha": "^2.5.3",
|
||||
"monaco-editor-core": "^0.3.1",
|
||||
"object-assign": "^4.1.0",
|
||||
"rimraf": "^2.5.2",
|
||||
"typescript": "1.8.10",
|
||||
"typescript-with-globs": "^0.1.4"
|
||||
}
|
||||
}
|
||||
540
src/languageFeatures.ts
Normal file
540
src/languageFeatures.ts
Normal file
|
|
@ -0,0 +1,540 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {LanguageServiceDefaults} from './typescript';
|
||||
import * as ts from '../lib/typescriptServices';
|
||||
import {TypeScriptWorker} from './worker';
|
||||
|
||||
import Uri = monaco.Uri;
|
||||
import Position = monaco.Position;
|
||||
import Range = monaco.Range;
|
||||
import Thenable = monaco.Thenable;
|
||||
import Promise = monaco.Promise;
|
||||
import CancellationToken = monaco.CancellationToken;
|
||||
import IDisposable = monaco.IDisposable;
|
||||
|
||||
export abstract class Adapter {
|
||||
|
||||
constructor(protected _worker: (first:Uri, ...more:Uri[]) => Promise<TypeScriptWorker>) {
|
||||
}
|
||||
|
||||
protected _positionToOffset(uri: Uri, position: monaco.IPosition): number {
|
||||
let model = monaco.editor.getModel(uri);
|
||||
return model.getOffsetAt(position);
|
||||
}
|
||||
|
||||
protected _offsetToPosition(uri: Uri, offset: number): monaco.IPosition {
|
||||
let model = monaco.editor.getModel(uri);
|
||||
return model.getPositionAt(offset);
|
||||
}
|
||||
|
||||
protected _textSpanToRange(uri: Uri, span: ts.TextSpan): monaco.IRange {
|
||||
let p1 = this._offsetToPosition(uri, span.start);
|
||||
let p2 = this._offsetToPosition(uri, span.start + span.length);
|
||||
let {lineNumber: startLineNumber, column: startColumn} = p1;
|
||||
let {lineNumber: endLineNumber, column: endColumn} = p2;
|
||||
return { startLineNumber, startColumn, endLineNumber, endColumn };
|
||||
}
|
||||
}
|
||||
|
||||
// --- diagnostics --- ---
|
||||
|
||||
export class DiagnostcsAdapter extends Adapter {
|
||||
|
||||
private _disposables: IDisposable[] = [];
|
||||
private _listener: { [uri: string]: IDisposable } = Object.create(null);
|
||||
|
||||
constructor(private _defaults: LanguageServiceDefaults, private _selector: string,
|
||||
worker: (first: Uri, ...more: Uri[]) => Promise<TypeScriptWorker>
|
||||
) {
|
||||
super(worker);
|
||||
|
||||
const onModelAdd = (model: monaco.editor.IModel): void => {
|
||||
if (model.getModeId() !== _selector) {
|
||||
return;
|
||||
}
|
||||
|
||||
let handle: number;
|
||||
this._listener[model.uri.toString()] = model.onDidChangeContent(() => {
|
||||
clearTimeout(handle);
|
||||
handle = setTimeout(() => this._doValidate(model.uri), 500);
|
||||
});
|
||||
|
||||
this._doValidate(model.uri);
|
||||
};
|
||||
|
||||
const onModelRemoved = (model: monaco.editor.IModel): void => {
|
||||
delete this._listener[model.uri.toString()];
|
||||
};
|
||||
|
||||
this._disposables.push(monaco.editor.onDidCreateModel(onModelAdd));
|
||||
this._disposables.push(monaco.editor.onWillDisposeModel(onModelRemoved));
|
||||
this._disposables.push(monaco.editor.onDidChangeModelLanguage(event => {
|
||||
onModelRemoved(event.model);
|
||||
onModelAdd(event.model);
|
||||
}));
|
||||
|
||||
this._disposables.push({
|
||||
dispose: () => {
|
||||
for (let key in this._listener) {
|
||||
this._listener[key].dispose();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
monaco.editor.getModels().forEach(onModelAdd);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._disposables.forEach(d => d && d.dispose());
|
||||
this._disposables = [];
|
||||
}
|
||||
|
||||
private _doValidate(resource: Uri): void {
|
||||
this._worker(resource).then(worker => {
|
||||
let promises: Promise<ts.Diagnostic[]>[] = [];
|
||||
if (!this._defaults.diagnosticsOptions.noSyntaxValidation) {
|
||||
promises.push(worker.getSyntacticDiagnostics(resource.toString()));
|
||||
}
|
||||
if (!this._defaults.diagnosticsOptions.noSemanticValidation) {
|
||||
promises.push(worker.getSemanticDiagnostics(resource.toString()));
|
||||
}
|
||||
return Promise.join(promises);
|
||||
}).then(diagnostics => {
|
||||
const markers = diagnostics
|
||||
.reduce((p, c) => c.concat(p), [])
|
||||
.map(d => this._convertDiagnostics(resource, d));
|
||||
|
||||
monaco.editor.setModelMarkers(monaco.editor.getModel(resource), this._selector, markers);
|
||||
}).done(undefined, err => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
private _convertDiagnostics(resource: Uri, diag: ts.Diagnostic): monaco.editor.IMarkerData {
|
||||
const {lineNumber: startLineNumber, column: startColumn} = this._offsetToPosition(resource, diag.start);
|
||||
const {lineNumber: endLineNumber, column: endColumn} = this._offsetToPosition(resource, diag.start + diag.length);
|
||||
|
||||
return {
|
||||
severity: monaco.Severity.Error,
|
||||
startLineNumber,
|
||||
startColumn,
|
||||
endLineNumber,
|
||||
endColumn,
|
||||
message: ts.flattenDiagnosticMessageText(diag.messageText, '\n')
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// --- suggest ------
|
||||
|
||||
interface MyCompletionItem extends monaco.languages.CompletionItem {
|
||||
uri: Uri;
|
||||
position: Position;
|
||||
}
|
||||
|
||||
export class SuggestAdapter extends Adapter implements monaco.languages.CompletionItemProvider {
|
||||
|
||||
public get triggerCharacters(): string[] {
|
||||
return ['.'];
|
||||
}
|
||||
|
||||
provideCompletionItems(model:monaco.editor.IReadOnlyModel, position:Position, token:CancellationToken): Thenable<monaco.languages.CompletionItem[]> {
|
||||
const wordInfo = model.getWordUntilPosition(position);
|
||||
const resource = model.uri;
|
||||
const offset = this._positionToOffset(resource, position);
|
||||
|
||||
return wireCancellationToken(token, this._worker(resource).then(worker => {
|
||||
return worker.getCompletionsAtPosition(resource.toString(), offset);
|
||||
}).then(info => {
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
let suggestions: MyCompletionItem[] = info.entries.map(entry => {
|
||||
return {
|
||||
uri: resource,
|
||||
position: position,
|
||||
label: entry.name,
|
||||
sortText: entry.sortText,
|
||||
kind: SuggestAdapter.convertKind(entry.kind)
|
||||
};
|
||||
});
|
||||
|
||||
return suggestions;
|
||||
}));
|
||||
}
|
||||
|
||||
resolveCompletionItem(item: monaco.languages.CompletionItem, token: CancellationToken): Thenable<monaco.languages.CompletionItem> {
|
||||
let myItem = <MyCompletionItem>item;
|
||||
const resource = myItem.uri;
|
||||
const position = myItem.position;
|
||||
|
||||
return wireCancellationToken(token, this._worker(resource).then(worker => {
|
||||
return worker.getCompletionEntryDetails(resource.toString(),
|
||||
this._positionToOffset(resource, position),
|
||||
myItem.label);
|
||||
|
||||
}).then(details => {
|
||||
if (!details) {
|
||||
return myItem;
|
||||
}
|
||||
return <MyCompletionItem>{
|
||||
uri: resource,
|
||||
position: position,
|
||||
label: details.name,
|
||||
kind: SuggestAdapter.convertKind(details.kind),
|
||||
detail: ts.displayPartsToString(details.displayParts),
|
||||
documentation: ts.displayPartsToString(details.documentation)
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
private static convertKind(kind: string): monaco.languages.CompletionItemKind {
|
||||
switch (kind) {
|
||||
case Kind.primitiveType:
|
||||
case Kind.keyword:
|
||||
return monaco.languages.CompletionItemKind.Keyword;
|
||||
case Kind.variable:
|
||||
case Kind.localVariable:
|
||||
return monaco.languages.CompletionItemKind.Variable;
|
||||
case Kind.memberVariable:
|
||||
case Kind.memberGetAccessor:
|
||||
case Kind.memberSetAccessor:
|
||||
return monaco.languages.CompletionItemKind.Field;
|
||||
case Kind.function:
|
||||
case Kind.memberFunction:
|
||||
case Kind.constructSignature:
|
||||
case Kind.callSignature:
|
||||
case Kind.indexSignature:
|
||||
return monaco.languages.CompletionItemKind.Function;
|
||||
case Kind.enum:
|
||||
return monaco.languages.CompletionItemKind.Enum;
|
||||
case Kind.module:
|
||||
return monaco.languages.CompletionItemKind.Module;
|
||||
case Kind.class:
|
||||
return monaco.languages.CompletionItemKind.Class;
|
||||
case Kind.interface:
|
||||
return monaco.languages.CompletionItemKind.Interface;
|
||||
case Kind.warning:
|
||||
return monaco.languages.CompletionItemKind.File;
|
||||
}
|
||||
|
||||
return monaco.languages.CompletionItemKind.Property;
|
||||
}
|
||||
}
|
||||
|
||||
export class SignatureHelpAdapter extends Adapter implements monaco.languages.SignatureHelpProvider {
|
||||
|
||||
public signatureHelpTriggerCharacters = ['(', ','];
|
||||
|
||||
provideSignatureHelp(model: monaco.editor.IReadOnlyModel, position: Position, token: CancellationToken): Thenable<monaco.languages.SignatureHelp> {
|
||||
let resource = model.uri;
|
||||
return wireCancellationToken(token, this._worker(resource).then(worker => worker.getSignatureHelpItems(resource.toString(), this._positionToOffset(resource, position))).then(info => {
|
||||
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
let ret:monaco.languages.SignatureHelp = {
|
||||
activeSignature: info.selectedItemIndex,
|
||||
activeParameter: info.argumentIndex,
|
||||
signatures: []
|
||||
};
|
||||
|
||||
info.items.forEach(item => {
|
||||
|
||||
let signature:monaco.languages.SignatureInformation = {
|
||||
label: '',
|
||||
documentation: null,
|
||||
parameters: []
|
||||
};
|
||||
|
||||
signature.label += ts.displayPartsToString(item.prefixDisplayParts);
|
||||
item.parameters.forEach((p, i, a) => {
|
||||
let label = ts.displayPartsToString(p.displayParts);
|
||||
let parameter:monaco.languages.ParameterInformation = {
|
||||
label: label,
|
||||
documentation: ts.displayPartsToString(p.documentation)
|
||||
};
|
||||
signature.label += label;
|
||||
signature.parameters.push(parameter);
|
||||
if (i < a.length - 1) {
|
||||
signature.label += ts.displayPartsToString(item.separatorDisplayParts);
|
||||
}
|
||||
});
|
||||
signature.label += ts.displayPartsToString(item.suffixDisplayParts);
|
||||
ret.signatures.push(signature);
|
||||
});
|
||||
|
||||
return ret;
|
||||
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// --- hover ------
|
||||
|
||||
export class QuickInfoAdapter extends Adapter implements monaco.languages.HoverProvider {
|
||||
|
||||
provideHover(model:monaco.editor.IReadOnlyModel, position:Position, token:CancellationToken): Thenable<monaco.languages.Hover> {
|
||||
let resource = model.uri;
|
||||
|
||||
return wireCancellationToken(token, this._worker(resource).then(worker => {
|
||||
return worker.getQuickInfoAtPosition(resource.toString(), this._positionToOffset(resource, position));
|
||||
}).then(info => {
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
return <monaco.languages.Hover>{
|
||||
range: this._textSpanToRange(resource, info.textSpan),
|
||||
htmlContent: [{ text: ts.displayPartsToString(info.displayParts) }]
|
||||
};
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// --- occurrences ------
|
||||
|
||||
export class OccurrencesAdapter extends Adapter implements monaco.languages.DocumentHighlightProvider {
|
||||
|
||||
public provideDocumentHighlights(model: monaco.editor.IReadOnlyModel, position: Position, token: CancellationToken): Thenable<monaco.languages.DocumentHighlight[]> {
|
||||
const resource = model.uri;
|
||||
|
||||
return wireCancellationToken(token, this._worker(resource).then(worker => {
|
||||
return worker.getOccurrencesAtPosition(resource.toString(), this._positionToOffset(resource, position));
|
||||
}).then(entries => {
|
||||
if (!entries) {
|
||||
return;
|
||||
}
|
||||
return entries.map(entry => {
|
||||
return <monaco.languages.DocumentHighlight>{
|
||||
range: this._textSpanToRange(resource, entry.textSpan),
|
||||
kind: entry.isWriteAccess ? monaco.languages.DocumentHighlightKind.Write : monaco.languages.DocumentHighlightKind.Text
|
||||
};
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// --- definition ------
|
||||
|
||||
export class DefinitionAdapter extends Adapter {
|
||||
|
||||
public provideDefinition(model:monaco.editor.IReadOnlyModel, position:Position, token:CancellationToken): Thenable<monaco.languages.Definition> {
|
||||
const resource = model.uri;
|
||||
|
||||
return wireCancellationToken(token, this._worker(resource).then(worker => {
|
||||
return worker.getDefinitionAtPosition(resource.toString(), this._positionToOffset(resource, position));
|
||||
}).then(entries => {
|
||||
if (!entries) {
|
||||
return;
|
||||
}
|
||||
const result: monaco.languages.Location[] = [];
|
||||
for (let entry of entries) {
|
||||
const uri = Uri.parse(entry.fileName);
|
||||
if (monaco.editor.getModel(uri)) {
|
||||
result.push({
|
||||
uri: uri,
|
||||
range: this._textSpanToRange(uri, entry.textSpan)
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// --- references ------
|
||||
|
||||
export class ReferenceAdapter extends Adapter implements monaco.languages.ReferenceProvider {
|
||||
|
||||
provideReferences(model:monaco.editor.IReadOnlyModel, position:Position, context: monaco.languages.ReferenceContext, token: CancellationToken): Thenable<monaco.languages.Location[]> {
|
||||
const resource = model.uri;
|
||||
|
||||
return wireCancellationToken(token, this._worker(resource).then(worker => {
|
||||
return worker.getReferencesAtPosition(resource.toString(), this._positionToOffset(resource, position));
|
||||
}).then(entries => {
|
||||
if (!entries) {
|
||||
return;
|
||||
}
|
||||
const result: monaco.languages.Location[] = [];
|
||||
for (let entry of entries) {
|
||||
const uri = Uri.parse(entry.fileName);
|
||||
if (monaco.editor.getModel(uri)) {
|
||||
result.push({
|
||||
uri: uri,
|
||||
range: this._textSpanToRange(uri, entry.textSpan)
|
||||
});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// --- outline ------
|
||||
|
||||
export class OutlineAdapter extends Adapter implements monaco.languages.DocumentSymbolProvider {
|
||||
|
||||
public provideDocumentSymbols(model:monaco.editor.IReadOnlyModel, token: CancellationToken): Thenable<monaco.languages.SymbolInformation[]> {
|
||||
const resource = model.uri;
|
||||
|
||||
return wireCancellationToken(token, this._worker(resource).then(worker => worker.getNavigationBarItems(resource.toString())).then(items => {
|
||||
if (!items) {
|
||||
return;
|
||||
}
|
||||
|
||||
function convert(bucket: monaco.languages.SymbolInformation[], item: ts.NavigationBarItem, containerLabel?: string): void {
|
||||
let result: monaco.languages.SymbolInformation = {
|
||||
name: item.text,
|
||||
kind: outlineTypeTable[item.kind] || monaco.languages.SymbolKind.Variable,
|
||||
location: {
|
||||
uri: resource,
|
||||
range: this._textSpanToRange(resource, item.spans[0])
|
||||
},
|
||||
containerName: containerLabel
|
||||
};
|
||||
|
||||
if (item.childItems && item.childItems.length > 0) {
|
||||
for (let child of item.childItems) {
|
||||
convert(bucket, child, result.name);
|
||||
}
|
||||
}
|
||||
|
||||
bucket.push(result);
|
||||
}
|
||||
|
||||
let result: monaco.languages.SymbolInformation[] = [];
|
||||
items.forEach(item => convert(result, item));
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export class Kind {
|
||||
public static unknown:string = '';
|
||||
public static keyword:string = 'keyword';
|
||||
public static script:string = 'script';
|
||||
public static module:string = 'module';
|
||||
public static class:string = 'class';
|
||||
public static interface:string = 'interface';
|
||||
public static type:string = 'type';
|
||||
public static enum:string = 'enum';
|
||||
public static variable:string = 'var';
|
||||
public static localVariable:string = 'local var';
|
||||
public static function:string = 'function';
|
||||
public static localFunction:string = 'local function';
|
||||
public static memberFunction:string = 'method';
|
||||
public static memberGetAccessor:string = 'getter';
|
||||
public static memberSetAccessor:string = 'setter';
|
||||
public static memberVariable:string = 'property';
|
||||
public static constructorImplementation:string = 'constructor';
|
||||
public static callSignature:string = 'call';
|
||||
public static indexSignature:string = 'index';
|
||||
public static constructSignature:string = 'construct';
|
||||
public static parameter:string = 'parameter';
|
||||
public static typeParameter:string = 'type parameter';
|
||||
public static primitiveType:string = 'primitive type';
|
||||
public static label:string = 'label';
|
||||
public static alias:string = 'alias';
|
||||
public static const:string = 'const';
|
||||
public static let:string = 'let';
|
||||
public static warning:string = 'warning';
|
||||
}
|
||||
|
||||
let outlineTypeTable: { [kind: string]: monaco.languages.SymbolKind } = Object.create(null);
|
||||
outlineTypeTable[Kind.module] = monaco.languages.SymbolKind.Module;
|
||||
outlineTypeTable[Kind.class] = monaco.languages.SymbolKind.Class;
|
||||
outlineTypeTable[Kind.enum] = monaco.languages.SymbolKind.Enum;
|
||||
outlineTypeTable[Kind.interface] = monaco.languages.SymbolKind.Interface;
|
||||
outlineTypeTable[Kind.memberFunction] = monaco.languages.SymbolKind.Method;
|
||||
outlineTypeTable[Kind.memberVariable] = monaco.languages.SymbolKind.Property;
|
||||
outlineTypeTable[Kind.memberGetAccessor] = monaco.languages.SymbolKind.Property;
|
||||
outlineTypeTable[Kind.memberSetAccessor] = monaco.languages.SymbolKind.Property;
|
||||
outlineTypeTable[Kind.variable] = monaco.languages.SymbolKind.Variable;
|
||||
outlineTypeTable[Kind.const] = monaco.languages.SymbolKind.Variable;
|
||||
outlineTypeTable[Kind.localVariable] = monaco.languages.SymbolKind.Variable;
|
||||
outlineTypeTable[Kind.variable] = monaco.languages.SymbolKind.Variable;
|
||||
outlineTypeTable[Kind.function] = monaco.languages.SymbolKind.Function;
|
||||
outlineTypeTable[Kind.localFunction] = monaco.languages.SymbolKind.Function;
|
||||
|
||||
// --- formatting ----
|
||||
|
||||
export abstract class FormatHelper extends Adapter {
|
||||
protected static _convertOptions(options: monaco.languages.IFormattingOptions): ts.FormatCodeOptions {
|
||||
return {
|
||||
ConvertTabsToSpaces: options.insertSpaces,
|
||||
TabSize: options.tabSize,
|
||||
IndentSize: options.tabSize,
|
||||
IndentStyle: ts.IndentStyle.Smart,
|
||||
NewLineCharacter: '\n',
|
||||
InsertSpaceAfterCommaDelimiter: true,
|
||||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
InsertSpaceAfterKeywordsInControlFlowStatements: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: true,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: true,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: true,
|
||||
InsertSpaceAfterSemicolonInForStatements: false,
|
||||
InsertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
PlaceOpenBraceOnNewLineForControlBlocks: false,
|
||||
PlaceOpenBraceOnNewLineForFunctions: false
|
||||
};
|
||||
}
|
||||
|
||||
protected _convertTextChanges(uri: Uri, change: ts.TextChange): monaco.editor.ISingleEditOperation {
|
||||
return <monaco.editor.ISingleEditOperation>{
|
||||
text: change.newText,
|
||||
range: this._textSpanToRange(uri, change.span)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class FormatAdapter extends FormatHelper implements monaco.languages.DocumentRangeFormattingEditProvider {
|
||||
|
||||
provideDocumentRangeFormattingEdits(model: monaco.editor.IReadOnlyModel, range: Range, options: monaco.languages.IFormattingOptions, token: CancellationToken): Thenable<monaco.editor.ISingleEditOperation[]> {
|
||||
const resource = model.uri;
|
||||
|
||||
return wireCancellationToken(token, this._worker(resource).then(worker => {
|
||||
return worker.getFormattingEditsForRange(resource.toString(),
|
||||
this._positionToOffset(resource, { lineNumber: range.startLineNumber, column: range.startColumn }),
|
||||
this._positionToOffset(resource, { lineNumber: range.endLineNumber, column: range.endColumn }),
|
||||
FormatHelper._convertOptions(options));
|
||||
}).then(edits => {
|
||||
if (edits) {
|
||||
return edits.map(edit => this._convertTextChanges(resource, edit));
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export class FormatOnTypeAdapter extends FormatHelper implements monaco.languages.OnTypeFormattingEditProvider {
|
||||
|
||||
get autoFormatTriggerCharacters() {
|
||||
return [';', '}', '\n'];
|
||||
}
|
||||
|
||||
provideOnTypeFormattingEdits(model: monaco.editor.IReadOnlyModel, position: Position, ch: string, options: monaco.languages.IFormattingOptions, token: CancellationToken): Thenable<monaco.editor.ISingleEditOperation[]> {
|
||||
const resource = model.uri;
|
||||
|
||||
return wireCancellationToken(token, this._worker(resource).then(worker => {
|
||||
return worker.getFormattingEditsAfterKeystroke(resource.toString(),
|
||||
this._positionToOffset(resource, position),
|
||||
ch, FormatHelper._convertOptions(options));
|
||||
}).then(edits => {
|
||||
if (edits) {
|
||||
return edits.map(edit => this._convertTextChanges(resource, edit));
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook a cancellation token to a WinJS Promise
|
||||
*/
|
||||
function wireCancellationToken<T>(token: CancellationToken, promise: Promise<T>): Thenable<T> {
|
||||
token.onCancellationRequested(() => promise.cancel());
|
||||
return promise;
|
||||
}
|
||||
110
src/mode.ts
Normal file
110
src/mode.ts
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {Language, createTokenizationSupport} from './tokenization';
|
||||
import {LanguageServiceDefaults, typeScriptDefaults, javaScriptDefaults, LanguageServiceMode} from './typescript';
|
||||
import {WorkerManager} from './workerManager';
|
||||
import {TypeScriptWorker} from './worker';
|
||||
import * as languageFeatures from './languageFeatures';
|
||||
|
||||
import Promise = monaco.Promise;
|
||||
import Uri = monaco.Uri;
|
||||
import IDisposable = monaco.IDisposable;
|
||||
|
||||
export function setupTypeScript(): void {
|
||||
setupMode(
|
||||
typeScriptDefaults,
|
||||
'typescript',
|
||||
Language.TypeScript
|
||||
);
|
||||
}
|
||||
|
||||
export function setupJavaScript(): void {
|
||||
setupMode(
|
||||
javaScriptDefaults,
|
||||
'javascript',
|
||||
Language.EcmaScript5
|
||||
);
|
||||
}
|
||||
|
||||
function setupMode(defaults:LanguageServiceDefaults, modeId:string, language:Language): void {
|
||||
|
||||
let disposables: IDisposable[] = [];
|
||||
|
||||
const client = new WorkerManager(defaults);
|
||||
disposables.push(client);
|
||||
|
||||
const worker = (first: Uri, ...more: Uri[]): Promise<TypeScriptWorker> => {
|
||||
return client.getLanguageServiceWorker(...[first].concat(more));
|
||||
};
|
||||
|
||||
disposables.push(monaco.languages.registerCompletionItemProvider(modeId, new languageFeatures.SuggestAdapter(worker)));
|
||||
disposables.push(monaco.languages.registerSignatureHelpProvider(modeId, new languageFeatures.SignatureHelpAdapter(worker)));
|
||||
disposables.push(monaco.languages.registerHoverProvider(modeId, new languageFeatures.QuickInfoAdapter(worker)));
|
||||
disposables.push(monaco.languages.registerDocumentHighlightProvider(modeId, new languageFeatures.OccurrencesAdapter(worker)));
|
||||
disposables.push(monaco.languages.registerDefinitionProvider(modeId, new languageFeatures.DefinitionAdapter(worker)));
|
||||
disposables.push(monaco.languages.registerReferenceProvider(modeId, new languageFeatures.ReferenceAdapter(worker)));
|
||||
disposables.push(monaco.languages.registerDocumentSymbolProvider(modeId, new languageFeatures.OutlineAdapter(worker)));
|
||||
disposables.push(monaco.languages.registerDocumentRangeFormattingEditProvider(modeId, new languageFeatures.FormatAdapter(worker)));
|
||||
disposables.push(monaco.languages.registerOnTypeFormattingEditProvider(modeId, new languageFeatures.FormatOnTypeAdapter(worker)));
|
||||
disposables.push(new languageFeatures.DiagnostcsAdapter(defaults, modeId, worker));
|
||||
disposables.push(monaco.languages.setLanguageConfiguration(modeId, richEditConfiguration));
|
||||
disposables.push(monaco.languages.setTokensProvider(modeId, createTokenizationSupport(language)));
|
||||
}
|
||||
|
||||
const richEditConfiguration:monaco.languages.IRichLanguageConfiguration = {
|
||||
wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
|
||||
|
||||
comments: {
|
||||
lineComment: '//',
|
||||
blockComment: ['/*', '*/']
|
||||
},
|
||||
|
||||
brackets: [
|
||||
['{', '}'],
|
||||
['[', ']'],
|
||||
['(', ')']
|
||||
],
|
||||
|
||||
onEnterRules: [
|
||||
{
|
||||
// e.g. /** | */
|
||||
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
|
||||
afterText: /^\s*\*\/$/,
|
||||
action: { indentAction: monaco.languages.IndentAction.IndentOutdent, appendText: ' * ' }
|
||||
},
|
||||
{
|
||||
// e.g. /** ...|
|
||||
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
|
||||
action: { indentAction: monaco.languages.IndentAction.None, appendText: ' * ' }
|
||||
},
|
||||
{
|
||||
// e.g. * ...|
|
||||
beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
|
||||
action: { indentAction: monaco.languages.IndentAction.None, appendText: '* ' }
|
||||
},
|
||||
{
|
||||
// e.g. */|
|
||||
beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/,
|
||||
action: { indentAction: monaco.languages.IndentAction.None, removeText: 1 }
|
||||
}
|
||||
],
|
||||
|
||||
__electricCharacterSupport: {
|
||||
docComment: {scope:'comment.doc', open:'/**', lineStart:' * ', close:' */'}
|
||||
},
|
||||
|
||||
autoClosingPairs: [
|
||||
{ open: '{', close: '}' },
|
||||
{ open: '[', close: ']' },
|
||||
{ open: '(', close: ')' },
|
||||
{ open: '"', close: '"', notIn: ['string'] },
|
||||
{ open: '\'', close: '\'', notIn: ['string', 'comment'] },
|
||||
{ open: '`', close: '`' }
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
35
src/monaco.contribution.ts
Normal file
35
src/monaco.contribution.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as mode from './mode';
|
||||
|
||||
declare var require:<T>(moduleId:[string], callback:(module:T)=>void)=>void;
|
||||
|
||||
function withMode(callback:(module:typeof mode)=>void): void {
|
||||
require<typeof mode>(['vs/language/typescript/src/mode'], callback);
|
||||
}
|
||||
|
||||
monaco.languages.register({
|
||||
id: 'typescript',
|
||||
extensions: ['.ts'],
|
||||
aliases: ['TypeScript', 'ts', 'typescript'],
|
||||
mimetypes: ['text/typescript']
|
||||
});
|
||||
monaco.languages.onLanguage('typescript', () => {
|
||||
withMode((mode) => mode.setupTypeScript());
|
||||
});
|
||||
|
||||
monaco.languages.register({
|
||||
id: 'javascript',
|
||||
extensions: ['.js', '.es6'],
|
||||
firstLine: '^#!.*\\bnode',
|
||||
filenames: ['jakefile'],
|
||||
aliases: ['JavaScript', 'javascript', 'js'],
|
||||
mimetypes: ['text/javascript'],
|
||||
});
|
||||
monaco.languages.onLanguage('javascript', () => {
|
||||
withMode((mode) => mode.setupJavaScript());
|
||||
});
|
||||
163
src/tokenization.ts
Normal file
163
src/tokenization.ts
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import ts = require('../lib/typescriptServices');
|
||||
|
||||
export enum Language {
|
||||
TypeScript,
|
||||
EcmaScript5
|
||||
}
|
||||
|
||||
export function createTokenizationSupport(language:Language): monaco.languages.TokensProvider {
|
||||
|
||||
var classifier = ts.createClassifier(),
|
||||
bracketTypeTable = language === Language.TypeScript ? tsBracketTypeTable : jsBracketTypeTable,
|
||||
tokenTypeTable = language === Language.TypeScript ? tsTokenTypeTable : jsTokenTypeTable;
|
||||
|
||||
return {
|
||||
getInitialState: () => new State(language, ts.EndOfLineState.None, false),
|
||||
tokenize: (line, state) => tokenize(bracketTypeTable, tokenTypeTable, classifier, <State> state, line)
|
||||
};
|
||||
}
|
||||
|
||||
class State implements monaco.languages.IState {
|
||||
|
||||
public language: Language;
|
||||
public eolState: ts.EndOfLineState;
|
||||
public inJsDocComment: boolean;
|
||||
|
||||
constructor(language:Language, eolState: ts.EndOfLineState, inJsDocComment: boolean) {
|
||||
this.language = language;
|
||||
this.eolState = eolState;
|
||||
this.inJsDocComment = inJsDocComment;
|
||||
}
|
||||
|
||||
public clone(): State {
|
||||
return new State(this.language, this.eolState, this.inJsDocComment);
|
||||
}
|
||||
|
||||
public equals(other:monaco.languages.IState):boolean {
|
||||
if(other === this) {
|
||||
return true;
|
||||
}
|
||||
if(!other || !(other instanceof State)) {
|
||||
return false;
|
||||
}
|
||||
if (this.eolState !== (<State> other).eolState) {
|
||||
return false;
|
||||
}
|
||||
if(this.inJsDocComment !== (<State> other).inJsDocComment) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function tokenize(bracketTypeTable: { [i: number]: string }, tokenTypeTable: { [i: number]: string },
|
||||
classifier: ts.Classifier, state: State, text: string): monaco.languages.ILineTokens {
|
||||
|
||||
// Create result early and fill in tokens
|
||||
var ret = {
|
||||
tokens: <monaco.languages.IToken[]>[],
|
||||
endState: new State(state.language, ts.EndOfLineState.None, false)
|
||||
};
|
||||
|
||||
function appendFn(startIndex:number, type:string):void {
|
||||
if(ret.tokens.length === 0 || ret.tokens[ret.tokens.length - 1].scopes !== type) {
|
||||
ret.tokens.push({
|
||||
startIndex: startIndex,
|
||||
scopes: type
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var isTypeScript = state.language === Language.TypeScript;
|
||||
|
||||
// shebang statement, #! /bin/node
|
||||
if (!isTypeScript && checkSheBang(0, text, appendFn)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
var result = classifier.getClassificationsForLine(text, state.eolState, true),
|
||||
offset = 0;
|
||||
|
||||
ret.endState.eolState = result.finalLexState;
|
||||
ret.endState.inJsDocComment = result.finalLexState === ts.EndOfLineState.InMultiLineCommentTrivia && (state.inJsDocComment || /\/\*\*.*$/.test(text));
|
||||
|
||||
for (let entry of result.entries) {
|
||||
|
||||
var type: string;
|
||||
|
||||
if (entry.classification === ts.TokenClass.Punctuation) {
|
||||
// punctions: check for brackets: (){}[]
|
||||
var ch = text.charCodeAt(offset);
|
||||
type = bracketTypeTable[ch] || tokenTypeTable[entry.classification];
|
||||
appendFn(offset, type);
|
||||
|
||||
} else if (entry.classification === ts.TokenClass.Comment) {
|
||||
// comments: check for JSDoc, block, and line comments
|
||||
if (ret.endState.inJsDocComment || /\/\*\*.*\*\//.test(text.substr(offset, entry.length))) {
|
||||
appendFn(offset, isTypeScript ? 'comment.doc.ts' : 'comment.doc.js');
|
||||
} else {
|
||||
appendFn(offset, isTypeScript ? 'comment.ts' : 'comment.js');
|
||||
}
|
||||
} else {
|
||||
// everything else
|
||||
appendFn(offset,
|
||||
tokenTypeTable[entry.classification] || '');
|
||||
}
|
||||
|
||||
offset += entry.length;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
interface INumberStringDictionary {
|
||||
[idx: number]: string;
|
||||
}
|
||||
|
||||
var tsBracketTypeTable:INumberStringDictionary = Object.create(null);
|
||||
tsBracketTypeTable['('.charCodeAt(0)] = 'delimiter.parenthesis.ts';
|
||||
tsBracketTypeTable[')'.charCodeAt(0)] = 'delimiter.parenthesis.ts';
|
||||
tsBracketTypeTable['{'.charCodeAt(0)] = 'delimiter.bracket.ts';
|
||||
tsBracketTypeTable['}'.charCodeAt(0)] = 'delimiter.bracket.ts';
|
||||
tsBracketTypeTable['['.charCodeAt(0)] = 'delimiter.array.ts';
|
||||
tsBracketTypeTable[']'.charCodeAt(0)] = 'delimiter.array.ts';
|
||||
|
||||
var tsTokenTypeTable:INumberStringDictionary = Object.create(null);
|
||||
tsTokenTypeTable[ts.TokenClass.Identifier] = 'identifier.ts';
|
||||
tsTokenTypeTable[ts.TokenClass.Keyword] = 'keyword.ts';
|
||||
tsTokenTypeTable[ts.TokenClass.Operator] = 'delimiter.ts';
|
||||
tsTokenTypeTable[ts.TokenClass.Punctuation] = 'delimiter.ts';
|
||||
tsTokenTypeTable[ts.TokenClass.NumberLiteral] = 'number.ts';
|
||||
tsTokenTypeTable[ts.TokenClass.RegExpLiteral] = 'regexp.ts';
|
||||
tsTokenTypeTable[ts.TokenClass.StringLiteral] = 'string.ts';
|
||||
|
||||
var jsBracketTypeTable:INumberStringDictionary = Object.create(null);
|
||||
jsBracketTypeTable['('.charCodeAt(0)] = 'delimiter.parenthesis.js';
|
||||
jsBracketTypeTable[')'.charCodeAt(0)] = 'delimiter.parenthesis.js';
|
||||
jsBracketTypeTable['{'.charCodeAt(0)] = 'delimiter.bracket.js';
|
||||
jsBracketTypeTable['}'.charCodeAt(0)] = 'delimiter.bracket.js';
|
||||
jsBracketTypeTable['['.charCodeAt(0)] = 'delimiter.array.js';
|
||||
jsBracketTypeTable[']'.charCodeAt(0)] = 'delimiter.array.js';
|
||||
|
||||
var jsTokenTypeTable:INumberStringDictionary = Object.create(null);
|
||||
jsTokenTypeTable[ts.TokenClass.Identifier] = 'identifier.js';
|
||||
jsTokenTypeTable[ts.TokenClass.Keyword] = 'keyword.js';
|
||||
jsTokenTypeTable[ts.TokenClass.Operator] = 'delimiter.js';
|
||||
jsTokenTypeTable[ts.TokenClass.Punctuation] = 'delimiter.js';
|
||||
jsTokenTypeTable[ts.TokenClass.NumberLiteral] = 'number.js';
|
||||
jsTokenTypeTable[ts.TokenClass.RegExpLiteral] = 'regexp.js';
|
||||
jsTokenTypeTable[ts.TokenClass.StringLiteral] = 'string.js';
|
||||
|
||||
|
||||
function checkSheBang(deltaOffset: number, line: string, appendFn: (startIndex: number, type: string) => void): boolean {
|
||||
if (line.indexOf('#!') === 0) {
|
||||
appendFn(deltaOffset, 'comment.shebang');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
96
src/typescript.ts
Normal file
96
src/typescript.ts
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as ts from '../lib/typescriptServices';
|
||||
import {TypeScriptWorker} from './worker';
|
||||
|
||||
import Emitter = monaco.Emitter;
|
||||
import Promise = monaco.Promise;
|
||||
import Uri = monaco.Uri;
|
||||
import IDisposable = monaco.IDisposable;
|
||||
|
||||
// --- TypeScript configuration and defaults ---------
|
||||
|
||||
export interface DiagnosticsOptions {
|
||||
noSemanticValidation?: boolean;
|
||||
noSyntaxValidation?: boolean;
|
||||
}
|
||||
|
||||
export class LanguageServiceDefaults {
|
||||
|
||||
private _onDidChange = new Emitter<LanguageServiceDefaults>();
|
||||
private _extraLibs: { [path: string]: string };
|
||||
private _compilerOptions: ts.CompilerOptions;
|
||||
private _diagnosticsOptions: DiagnosticsOptions;
|
||||
|
||||
constructor(compilerOptions: ts.CompilerOptions, diagnosticsOptions: DiagnosticsOptions) {
|
||||
this._extraLibs = Object.create(null);
|
||||
this.setCompilerOptions(compilerOptions);
|
||||
this.setDiagnosticsOptions(diagnosticsOptions);
|
||||
}
|
||||
|
||||
get onDidChange(): monaco.IEvent<LanguageServiceDefaults>{
|
||||
return this._onDidChange.event;
|
||||
}
|
||||
|
||||
get extraLibs(): { [path: string]: string } {
|
||||
return Object.freeze(this._extraLibs);
|
||||
}
|
||||
|
||||
addExtraLib(content: string, filePath?: string): IDisposable {
|
||||
if (typeof filePath === 'undefined') {
|
||||
filePath = `ts:extralib-${Date.now()}`;
|
||||
}
|
||||
|
||||
if (this._extraLibs[filePath]) {
|
||||
throw new Error(`${filePath} already a extra lib`);
|
||||
}
|
||||
|
||||
this._extraLibs[filePath] = content;
|
||||
this._onDidChange.fire(this);
|
||||
|
||||
return {
|
||||
dispose: () => {
|
||||
if (delete this._extraLibs[filePath]) {
|
||||
this._onDidChange.fire(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get compilerOptions(): ts.CompilerOptions {
|
||||
return this._compilerOptions;
|
||||
}
|
||||
|
||||
setCompilerOptions(options: ts.CompilerOptions): void {
|
||||
this._compilerOptions = options || Object.create(null);
|
||||
this._onDidChange.fire(this);
|
||||
}
|
||||
|
||||
get diagnosticsOptions(): DiagnosticsOptions {
|
||||
return this._diagnosticsOptions;
|
||||
}
|
||||
|
||||
setDiagnosticsOptions(options: DiagnosticsOptions): void {
|
||||
this._diagnosticsOptions = options || Object.create(null);
|
||||
this._onDidChange.fire(this);
|
||||
}
|
||||
}
|
||||
|
||||
export const typeScriptDefaults = new LanguageServiceDefaults(
|
||||
{ allowNonTsExtensions: true, target: ts.ScriptTarget.Latest },
|
||||
{ noSemanticValidation: false, noSyntaxValidation: false });
|
||||
|
||||
export const javaScriptDefaults = new LanguageServiceDefaults(
|
||||
{ allowNonTsExtensions: true, allowJs: true, target: ts.ScriptTarget.Latest },
|
||||
{ noSemanticValidation: true, noSyntaxValidation: false });
|
||||
|
||||
|
||||
// --- TypeScript worker protocol ---------
|
||||
|
||||
export interface LanguageServiceMode {
|
||||
getLanguageServiceWorker(...resources: Uri[]): Promise<TypeScriptWorker>;
|
||||
}
|
||||
181
src/worker.ts
Normal file
181
src/worker.ts
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import ts = require('../lib/typescriptServices');
|
||||
import {contents as libdts} from '../lib/lib-ts';
|
||||
import {contents as libes6ts} from '../lib/lib-es6-ts';
|
||||
|
||||
import Promise = monaco.Promise;
|
||||
|
||||
const DEFAULT_LIB = {
|
||||
NAME: 'defaultLib:lib.d.ts',
|
||||
CONTENTS: libdts
|
||||
};
|
||||
|
||||
const ES6_LIB = {
|
||||
NAME: 'defaultLib:lib.es6.d.ts',
|
||||
CONTENTS: libes6ts
|
||||
};
|
||||
|
||||
export class TypeScriptWorker implements ts.LanguageServiceHost {
|
||||
|
||||
// --- model sync -----------------------
|
||||
|
||||
// private _models: { [uri: string]: MirrorModel2 } = Object.create(null);
|
||||
private _extraLibs: { [fileName: string]: string } = Object.create(null);
|
||||
private _languageService = ts.createLanguageService(this);
|
||||
private _compilerOptions: ts.CompilerOptions;
|
||||
|
||||
// --- default ---------
|
||||
|
||||
acceptDefaults(options:ts.CompilerOptions, extraLibs:{ [path: string]: string }): Promise<void> {
|
||||
this._compilerOptions = options;
|
||||
this._extraLibs = extraLibs;
|
||||
return;
|
||||
}
|
||||
|
||||
// --- language service host ---------------
|
||||
|
||||
getCompilationSettings(): ts.CompilerOptions {
|
||||
return this._compilerOptions;
|
||||
}
|
||||
|
||||
getScriptFileNames(): string[] {
|
||||
let models = monaco.worker.mirrorModels.map(model => model.uri.toString());
|
||||
return models.concat(Object.keys(this._extraLibs));
|
||||
}
|
||||
|
||||
private _getModel(fileName:string): monaco.worker.IMirrorModel {
|
||||
let models = monaco.worker.mirrorModels;
|
||||
for (let i = 0; i < models.length; i++) {
|
||||
if (models[i].uri.toString() === fileName) {
|
||||
return models[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getScriptVersion(fileName: string): string {
|
||||
let model = this._getModel(fileName);
|
||||
if (model) {
|
||||
return model.version.toString();
|
||||
} else if (this.isDefaultLibFileName(fileName) || fileName in this._extraLibs) {
|
||||
// extra lib and default lib are static
|
||||
return '1';
|
||||
}
|
||||
}
|
||||
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
|
||||
let text: string;
|
||||
let model = this._getModel(fileName);
|
||||
if (model) {
|
||||
// a true editor model
|
||||
text = model.getText();
|
||||
|
||||
} else if (fileName in this._extraLibs) {
|
||||
// static extra lib
|
||||
text = this._extraLibs[fileName];
|
||||
|
||||
} else if (fileName === DEFAULT_LIB.NAME) {
|
||||
text = DEFAULT_LIB.CONTENTS;
|
||||
} else if (fileName === ES6_LIB.NAME) {
|
||||
text = ES6_LIB.CONTENTS;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
return <ts.IScriptSnapshot>{
|
||||
getText: (start, end) => text.substring(start, end),
|
||||
getLength: () => text.length,
|
||||
getChangeRange: () => undefined
|
||||
};
|
||||
}
|
||||
|
||||
getCurrentDirectory(): string {
|
||||
return '';
|
||||
}
|
||||
|
||||
getDefaultLibFileName(options: ts.CompilerOptions): string {
|
||||
// TODO@joh support lib.es7.d.ts
|
||||
return options.target > ts.ScriptTarget.ES5 ? DEFAULT_LIB.NAME : ES6_LIB.NAME;
|
||||
}
|
||||
|
||||
isDefaultLibFileName(fileName: string): boolean {
|
||||
return fileName === this.getDefaultLibFileName(this._compilerOptions);
|
||||
}
|
||||
|
||||
// --- language features
|
||||
|
||||
getSyntacticDiagnostics(fileName: string): Promise<ts.Diagnostic[]> {
|
||||
const diagnostics = this._languageService.getSyntacticDiagnostics(fileName);
|
||||
diagnostics.forEach(diag => diag.file = undefined); // diag.file cannot be JSON'yfied
|
||||
return Promise.as(diagnostics);
|
||||
}
|
||||
|
||||
getSemanticDiagnostics(fileName: string): Promise<ts.Diagnostic[]> {
|
||||
const diagnostics = this._languageService.getSemanticDiagnostics(fileName);
|
||||
diagnostics.forEach(diag => diag.file = undefined); // diag.file cannot be JSON'yfied
|
||||
return Promise.as(diagnostics);
|
||||
}
|
||||
|
||||
getCompilerOptionsDiagnostics(fileName: string): Promise<ts.Diagnostic[]> {
|
||||
const diagnostics = this._languageService.getCompilerOptionsDiagnostics();
|
||||
diagnostics.forEach(diag => diag.file = undefined); // diag.file cannot be JSON'yfied
|
||||
return Promise.as(diagnostics);
|
||||
}
|
||||
|
||||
getCompletionsAtPosition(fileName: string, position:number): Promise<ts.CompletionInfo> {
|
||||
return Promise.as(this._languageService.getCompletionsAtPosition(fileName, position));
|
||||
}
|
||||
|
||||
getCompletionEntryDetails(fileName: string, position: number, entry: string): Promise<ts.CompletionEntryDetails> {
|
||||
return Promise.as(this._languageService.getCompletionEntryDetails(fileName, position, entry));
|
||||
}
|
||||
|
||||
getSignatureHelpItems(fileName: string, position:number): Promise<ts.SignatureHelpItems> {
|
||||
return Promise.as(this._languageService.getSignatureHelpItems(fileName, position));
|
||||
}
|
||||
|
||||
getQuickInfoAtPosition(fileName: string, position: number): Promise<ts.QuickInfo> {
|
||||
return Promise.as(this._languageService.getQuickInfoAtPosition(fileName, position));
|
||||
}
|
||||
|
||||
getOccurrencesAtPosition(fileName: string, position: number): Promise<ts.ReferenceEntry[]> {
|
||||
return Promise.as(this._languageService.getOccurrencesAtPosition(fileName, position));
|
||||
}
|
||||
|
||||
getDefinitionAtPosition(fileName: string, position: number): Promise<ts.DefinitionInfo[]> {
|
||||
return Promise.as(this._languageService.getDefinitionAtPosition(fileName, position));
|
||||
}
|
||||
|
||||
getReferencesAtPosition(fileName: string, position: number): Promise<ts.ReferenceEntry[]> {
|
||||
return Promise.as(this._languageService.getReferencesAtPosition(fileName, position));
|
||||
}
|
||||
|
||||
getNavigationBarItems(fileName: string): Promise<ts.NavigationBarItem[]> {
|
||||
return Promise.as(this._languageService.getNavigationBarItems(fileName));
|
||||
}
|
||||
|
||||
getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
|
||||
return Promise.as(this._languageService.getFormattingEditsForDocument(fileName, options));
|
||||
}
|
||||
|
||||
getFormattingEditsForRange(fileName: string, start: number, end: number, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
|
||||
return Promise.as(this._languageService.getFormattingEditsForRange(fileName, start, end, options));
|
||||
}
|
||||
|
||||
getFormattingEditsAfterKeystroke(fileName: string, postion: number, ch: string, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
|
||||
return Promise.as(this._languageService.getFormattingEditsAfterKeystroke(fileName, postion, ch, options));
|
||||
}
|
||||
|
||||
getEmitOutput(fileName: string): Promise<ts.EmitOutput> {
|
||||
return Promise.as(this._languageService.getEmitOutput(fileName));
|
||||
}
|
||||
}
|
||||
|
||||
export function create(): TypeScriptWorker {
|
||||
return new TypeScriptWorker();
|
||||
}
|
||||
104
src/workerManager.ts
Normal file
104
src/workerManager.ts
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {LanguageServiceMode, LanguageServiceDefaults} from './typescript';
|
||||
import {TypeScriptWorker} from './worker';
|
||||
|
||||
import Promise = monaco.Promise;
|
||||
import IDisposable = monaco.IDisposable;
|
||||
import Uri = monaco.Uri;
|
||||
|
||||
const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000; // 2min
|
||||
|
||||
export class WorkerManager {
|
||||
|
||||
private _defaults: LanguageServiceDefaults;
|
||||
private _idleCheckInterval: number;
|
||||
private _lastUsedTime: number;
|
||||
private _configChangeListener: IDisposable;
|
||||
|
||||
private _worker: monaco.editor.MonacoWebWorker<TypeScriptWorker>;
|
||||
private _client: Promise<TypeScriptWorker>;
|
||||
|
||||
constructor(defaults: LanguageServiceDefaults) {
|
||||
this._defaults = defaults;
|
||||
this._worker = null;
|
||||
this._idleCheckInterval = setInterval(() => this._checkIfIdle(), 30 * 1000);
|
||||
this._lastUsedTime = 0;
|
||||
this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker());
|
||||
}
|
||||
|
||||
private _stopWorker(): void {
|
||||
if (this._worker) {
|
||||
this._worker.dispose();
|
||||
this._worker = null;
|
||||
}
|
||||
this._client = null;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
clearInterval(this._idleCheckInterval);
|
||||
this._configChangeListener.dispose();
|
||||
this._stopWorker();
|
||||
}
|
||||
|
||||
private _checkIfIdle(): void {
|
||||
if (!this._worker) {
|
||||
return;
|
||||
}
|
||||
let timePassedSinceLastUsed = Date.now() - this._lastUsedTime;
|
||||
if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) {
|
||||
this._stopWorker();
|
||||
}
|
||||
}
|
||||
|
||||
private _getClient(): Promise<TypeScriptWorker> {
|
||||
this._lastUsedTime = Date.now();
|
||||
|
||||
if (!this._client) {
|
||||
this._worker = monaco.editor.createWebWorker<TypeScriptWorker>({
|
||||
moduleId: 'vs/language/typescript/src/worker',
|
||||
});
|
||||
|
||||
let _client:TypeScriptWorker = null;
|
||||
|
||||
// avoid cancellation
|
||||
this._client = toShallowCancelPromise(
|
||||
this._worker.getProxy().then((client) => {
|
||||
_client = client;
|
||||
}).then(_ => {
|
||||
const {compilerOptions, extraLibs} = this._defaults;
|
||||
return _client.acceptDefaults(compilerOptions, extraLibs);
|
||||
}).then(_ => _client)
|
||||
);
|
||||
}
|
||||
|
||||
return this._client;
|
||||
}
|
||||
|
||||
getLanguageServiceWorker(...resources: Uri[]): Promise<TypeScriptWorker> {
|
||||
let _client:TypeScriptWorker;
|
||||
return this._getClient().then((client) => {
|
||||
_client = client
|
||||
}).then(_ => {
|
||||
return this._worker.withSyncedResources(resources)
|
||||
}).then(_ => _client);
|
||||
}
|
||||
}
|
||||
|
||||
function toShallowCancelPromise<T>(p:Promise<T>): Promise<T> {
|
||||
let completeCallback: (value:T)=>void;
|
||||
let errorCallback: (err:any)=>void;
|
||||
|
||||
let r = new Promise<T>((c, e) => {
|
||||
completeCallback = c;
|
||||
errorCallback = e;
|
||||
}, () => { });
|
||||
|
||||
p.then(completeCallback, errorCallback);
|
||||
|
||||
return r;
|
||||
}
|
||||
12
test/all.js
Normal file
12
test/all.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
var requirejs = require("requirejs");
|
||||
|
||||
requirejs.config({
|
||||
baseUrl: 'out',
|
||||
nodeRequire: require
|
||||
});
|
||||
|
||||
requirejs([
|
||||
'test/tokenization.test'
|
||||
], function() {
|
||||
run(); // We can launch the tests!
|
||||
});
|
||||
44
test/assert.d.ts
vendored
Normal file
44
test/assert.d.ts
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
declare module "assert" {
|
||||
function internal (value: any, message?: string): void;
|
||||
namespace internal {
|
||||
export class AssertionError implements Error {
|
||||
name: string;
|
||||
message: string;
|
||||
actual: any;
|
||||
expected: any;
|
||||
operator: string;
|
||||
generatedMessage: boolean;
|
||||
|
||||
constructor(options?: {message?: string; actual?: any; expected?: any;
|
||||
operator?: string; stackStartFunction?: Function});
|
||||
}
|
||||
|
||||
export function fail(actual?: any, expected?: any, message?: string, operator?: string): void;
|
||||
export function ok(value: any, message?: string): void;
|
||||
export function equal(actual: any, expected: any, message?: string): void;
|
||||
export function notEqual(actual: any, expected: any, message?: string): void;
|
||||
export function deepEqual(actual: any, expected: any, message?: string): void;
|
||||
export function notDeepEqual(acutal: any, expected: any, message?: string): void;
|
||||
export function strictEqual(actual: any, expected: any, message?: string): void;
|
||||
export function notStrictEqual(actual: any, expected: any, message?: string): void;
|
||||
export function deepStrictEqual(actual: any, expected: any, message?: string): void;
|
||||
export function notDeepStrictEqual(actual: any, expected: any, message?: string): void;
|
||||
export var throws: {
|
||||
(block: Function, message?: string): void;
|
||||
(block: Function, error: Function, message?: string): void;
|
||||
(block: Function, error: RegExp, message?: string): void;
|
||||
(block: Function, error: (err: any) => boolean, message?: string): void;
|
||||
};
|
||||
|
||||
export var doesNotThrow: {
|
||||
(block: Function, message?: string): void;
|
||||
(block: Function, error: Function, message?: string): void;
|
||||
(block: Function, error: RegExp, message?: string): void;
|
||||
(block: Function, error: (err: any) => boolean, message?: string): void;
|
||||
};
|
||||
|
||||
export function ifError(value: any): void;
|
||||
}
|
||||
|
||||
export = internal;
|
||||
}
|
||||
13
test/mocha.d.ts
vendored
Normal file
13
test/mocha.d.ts
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare function run(): void;
|
||||
|
||||
declare function suite(name: string, fn: (err?)=>void);
|
||||
declare function test(name: string, fn: (done?: (err?)=>void)=>void);
|
||||
declare function suiteSetup(fn: (done?: (err?)=>void)=>void);
|
||||
declare function suiteTeardown(fn: (done?: (err?)=>void)=>void);
|
||||
declare function setup(fn: (done?: (err?)=>void)=>void);
|
||||
declare function teardown(fn: (done?: (err?)=>void)=>void);
|
||||
3
test/mocha.opts
Normal file
3
test/mocha.opts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
--delay
|
||||
--ui tdd
|
||||
test/all.js
|
||||
502
test/tokenization.test.ts
Normal file
502
test/tokenization.test.ts
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import {createTokenizationSupport, Language} from '../src/tokenization';
|
||||
|
||||
suite('tokenization', () => {
|
||||
|
||||
interface ITestItem {
|
||||
line: string;
|
||||
tokens: monaco.languages.IToken[];
|
||||
}
|
||||
|
||||
function executeTokenizationTests(tests:ITestItem[][]): void {
|
||||
let tokenizationSupport = createTokenizationSupport(Language.EcmaScript5);
|
||||
for (let i = 0, len = tests.length; i < len; i++) {
|
||||
assert.ok(true, 'TEST #' + i);
|
||||
executeTokenizationTest(tokenizationSupport, tests[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function executeTokenizationTest(tokenizationSupport: monaco.languages.TokensProvider, tests:ITestItem[]): void {
|
||||
let state = tokenizationSupport.getInitialState();
|
||||
for (let i = 0, len = tests.length; i < len; i++) {
|
||||
assert.ok(true, tests[i].line);
|
||||
|
||||
let result = tokenizationSupport.tokenize(tests[i].line, state);
|
||||
|
||||
if (tests[i].tokens) {
|
||||
assert.deepEqual(result.tokens, tests[i].tokens, 'Tokenizing line ' + tests[i].line + ': ' + JSON.stringify(tests[i].tokens, null, '\t'));
|
||||
}
|
||||
|
||||
state = result.endState;
|
||||
}
|
||||
}
|
||||
|
||||
test('', () => {
|
||||
executeTokenizationTests([
|
||||
|
||||
// Keywords
|
||||
[{
|
||||
line: 'var x = function() { };',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'keyword.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'identifier.js' },
|
||||
{ startIndex: 5, scopes: '' },
|
||||
{ startIndex: 6, scopes: 'delimiter.js' },
|
||||
{ startIndex: 7, scopes: '' },
|
||||
{ startIndex: 8, scopes: 'keyword.js' },
|
||||
{ startIndex: 16, scopes: 'delimiter.parenthesis.js' },
|
||||
{ startIndex: 18, scopes: '' },
|
||||
{ startIndex: 19, scopes: 'delimiter.bracket.js' },
|
||||
{ startIndex: 20, scopes: '' },
|
||||
{ startIndex: 21, scopes: 'delimiter.bracket.js' },
|
||||
{ startIndex: 22, scopes: 'delimiter.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: ' var ',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'keyword.js' },
|
||||
{ startIndex: 7, scopes: '' }
|
||||
]}],
|
||||
|
||||
// Comments - single line
|
||||
[{
|
||||
line: '//',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: ' // a comment',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '// a comment',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '// a comment /*',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '// a comment /**',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '//sticky comment',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: 'var x = 1; // my comment // is a nice one',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'keyword.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'identifier.js' },
|
||||
{ startIndex: 5, scopes: '' },
|
||||
{ startIndex: 6, scopes: 'delimiter.js' },
|
||||
{ startIndex: 7, scopes: '' },
|
||||
{ startIndex: 8, scopes: 'number.js' },
|
||||
{ startIndex: 9, scopes: 'delimiter.js' },
|
||||
{ startIndex: 10, scopes: '' },
|
||||
{ startIndex: 11, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
// Comments - range comment, single line
|
||||
[{
|
||||
line: '/* a simple comment */',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: 'var x = /* a simple comment */ 1;',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'keyword.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'identifier.js' },
|
||||
{ startIndex: 5, scopes: '' },
|
||||
{ startIndex: 6, scopes: 'delimiter.js' },
|
||||
{ startIndex: 7, scopes: '' },
|
||||
{ startIndex: 8, scopes: 'comment.js' },
|
||||
{ startIndex: 30, scopes: '' },
|
||||
{ startIndex: 31, scopes: 'number.js' },
|
||||
{ startIndex: 32, scopes: 'delimiter.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: 'x = /**/;',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'identifier.js' },
|
||||
{ startIndex: 1, scopes: '' },
|
||||
{ startIndex: 2, scopes: 'delimiter.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'comment.js' },
|
||||
{ startIndex: 8, scopes: 'delimiter.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: 'x = /*/;',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'identifier.js' },
|
||||
{ startIndex: 1, scopes: '' },
|
||||
{ startIndex: 2, scopes: 'delimiter.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
// Comments - range comment, multi lines
|
||||
[{
|
||||
line: '/* a multiline comment',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}, {
|
||||
line: 'can actually span',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}, {
|
||||
line: 'multiple lines */',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: 'var x = /* start a comment',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'keyword.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'identifier.js' },
|
||||
{ startIndex: 5, scopes: '' },
|
||||
{ startIndex: 6, scopes: 'delimiter.js' },
|
||||
{ startIndex: 7, scopes: '' },
|
||||
{ startIndex: 8, scopes: 'comment.js' }
|
||||
]}, {
|
||||
line: ' a ',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}, {
|
||||
line: 'and end it */ var a = 2;',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' },
|
||||
{ startIndex: 13, scopes: '' },
|
||||
{ startIndex: 14, scopes: 'keyword.js' },
|
||||
{ startIndex: 17, scopes: '' },
|
||||
{ startIndex: 18, scopes: 'identifier.js' },
|
||||
{ startIndex: 19, scopes: '' },
|
||||
{ startIndex: 20, scopes: 'delimiter.js' },
|
||||
{ startIndex: 21, scopes: '' },
|
||||
{ startIndex: 22, scopes: 'number.js' },
|
||||
{ startIndex: 23, scopes: 'delimiter.js' }
|
||||
]}],
|
||||
|
||||
// Strings
|
||||
[{
|
||||
line: 'var a = \'a\';',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'keyword.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'identifier.js' },
|
||||
{ startIndex: 5, scopes: '' },
|
||||
{ startIndex: 6, scopes: 'delimiter.js' },
|
||||
{ startIndex: 7, scopes: '' },
|
||||
{ startIndex: 8, scopes: 'string.js' },
|
||||
{ startIndex: 11, scopes: 'delimiter.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '"use strict";',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'string.js' },
|
||||
{ startIndex: 12, scopes: 'delimiter.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: 'b = a + " \'cool\' "',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'identifier.js' },
|
||||
{ startIndex: 1, scopes: '' },
|
||||
{ startIndex: 2, scopes: 'delimiter.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'identifier.js' },
|
||||
{ startIndex: 5, scopes: '' },
|
||||
{ startIndex: 6, scopes: 'delimiter.js' },
|
||||
{ startIndex: 7, scopes: '' },
|
||||
{ startIndex: 8, scopes: 'string.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '"escaping \\"quotes\\" is cool"',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'string.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '\'\'\'',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'string.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '\'\\\'\'',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'string.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '\'be careful \\not to escape\'',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'string.js' }
|
||||
]}],
|
||||
|
||||
// Numbers
|
||||
[{
|
||||
line: '0',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: ' 0',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: '' },
|
||||
{ startIndex: 1, scopes: 'number.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: ' 0 ',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: '' },
|
||||
{ startIndex: 1, scopes: 'number.js' },
|
||||
{ startIndex: 2, scopes: '' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '0 ',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' },
|
||||
{ startIndex: 1, scopes: '' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '0+0',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' },
|
||||
{ startIndex: 1, scopes: 'delimiter.js' },
|
||||
{ startIndex: 2, scopes: 'number.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '100+10',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' },
|
||||
{ startIndex: 3, scopes: 'delimiter.js' },
|
||||
{ startIndex: 4, scopes: 'number.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '0 + 0',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' },
|
||||
{ startIndex: 1, scopes: '' },
|
||||
{ startIndex: 2, scopes: 'delimiter.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'number.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '0123',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '01239',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '0x',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' },
|
||||
{ startIndex: 1, scopes: 'identifier.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '0x123',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' }
|
||||
]}],
|
||||
|
||||
// Regular Expressions
|
||||
[{
|
||||
line: '//',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '/**/',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '/***/',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'comment.doc.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '5 / 3;',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' },
|
||||
{ startIndex: 1, scopes: '' },
|
||||
{ startIndex: 2, scopes: 'delimiter.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'number.js' },
|
||||
{ startIndex: 5, scopes: 'delimiter.js' }
|
||||
]}],
|
||||
|
||||
// Advanced regular expressions
|
||||
[{
|
||||
line: '1 / 2; /* comment',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' },
|
||||
{ startIndex: 1, scopes: '' },
|
||||
{ startIndex: 2, scopes: 'delimiter.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'number.js' },
|
||||
{ startIndex: 5, scopes: 'delimiter.js' },
|
||||
{ startIndex: 6, scopes: '' },
|
||||
{ startIndex: 7, scopes: 'comment.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '1 / 2 / x / b;',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' },
|
||||
{ startIndex: 1, scopes: '' },
|
||||
{ startIndex: 2, scopes: 'delimiter.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'number.js' },
|
||||
{ startIndex: 5, scopes: '' },
|
||||
{ startIndex: 6, scopes: 'delimiter.js' },
|
||||
{ startIndex: 7, scopes: '' },
|
||||
{ startIndex: 8, scopes: 'identifier.js' },
|
||||
{ startIndex: 9, scopes: '' },
|
||||
{ startIndex: 10, scopes: 'delimiter.js' },
|
||||
{ startIndex: 11, scopes: '' },
|
||||
{ startIndex: 12, scopes: 'identifier.js' },
|
||||
{ startIndex: 13, scopes: 'delimiter.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: 'a /ads/ b;',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'identifier.js' },
|
||||
{ startIndex: 1, scopes: '' },
|
||||
{ startIndex: 2, scopes: 'delimiter.js' },
|
||||
{ startIndex: 3, scopes: 'identifier.js' },
|
||||
{ startIndex: 6, scopes: 'delimiter.js' },
|
||||
{ startIndex: 7, scopes: '' },
|
||||
{ startIndex: 8, scopes: 'identifier.js' },
|
||||
{ startIndex: 9, scopes: 'delimiter.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '1/(2/3)/2/3;',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'number.js' },
|
||||
{ startIndex: 1, scopes: 'delimiter.js' },
|
||||
{ startIndex: 2, scopes: 'delimiter.parenthesis.js' },
|
||||
{ startIndex: 3, scopes: 'number.js' },
|
||||
{ startIndex: 4, scopes: 'delimiter.js' },
|
||||
{ startIndex: 5, scopes: 'number.js' },
|
||||
{ startIndex: 6, scopes: 'delimiter.parenthesis.js' },
|
||||
{ startIndex: 7, scopes: 'delimiter.js' },
|
||||
{ startIndex: 8, scopes: 'number.js' },
|
||||
{ startIndex: 9, scopes: 'delimiter.js' },
|
||||
{ startIndex: 10, scopes: 'number.js' },
|
||||
{ startIndex: 11, scopes: 'delimiter.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '{ key: 123 }',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'delimiter.bracket.js' },
|
||||
{ startIndex: 1, scopes: '' },
|
||||
{ startIndex: 2, scopes: 'identifier.js' },
|
||||
{ startIndex: 5, scopes: 'delimiter.js' },
|
||||
{ startIndex: 6, scopes: '' },
|
||||
{ startIndex: 7, scopes: 'number.js' },
|
||||
{ startIndex: 10, scopes: '' },
|
||||
{ startIndex: 11, scopes: 'delimiter.bracket.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '[1,2,3]',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'delimiter.array.js' },
|
||||
{ startIndex: 1, scopes: 'number.js' },
|
||||
{ startIndex: 2, scopes: 'delimiter.js' },
|
||||
{ startIndex: 3, scopes: 'number.js' },
|
||||
{ startIndex: 4, scopes: 'delimiter.js' },
|
||||
{ startIndex: 5, scopes: 'number.js' },
|
||||
{ startIndex: 6, scopes: 'delimiter.array.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: 'foo(123);',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'identifier.js' },
|
||||
{ startIndex: 3, scopes: 'delimiter.parenthesis.js' },
|
||||
{ startIndex: 4, scopes: 'number.js' },
|
||||
{ startIndex: 7, scopes: 'delimiter.parenthesis.js' },
|
||||
{ startIndex: 8, scopes: 'delimiter.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: '{a:{b:[]}}',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'delimiter.bracket.js' },
|
||||
{ startIndex: 1, scopes: 'identifier.js' },
|
||||
{ startIndex: 2, scopes: 'delimiter.js' },
|
||||
{ startIndex: 3, scopes: 'delimiter.bracket.js' },
|
||||
{ startIndex: 4, scopes: 'identifier.js' },
|
||||
{ startIndex: 5, scopes: 'delimiter.js' },
|
||||
{ startIndex: 6, scopes: 'delimiter.array.js' },
|
||||
{ startIndex: 8, scopes: 'delimiter.bracket.js' }
|
||||
]}],
|
||||
|
||||
[{
|
||||
line: 'x = "[{()}]"',
|
||||
tokens: [
|
||||
{ startIndex: 0, scopes: 'identifier.js' },
|
||||
{ startIndex: 1, scopes: '' },
|
||||
{ startIndex: 2, scopes: 'delimiter.js' },
|
||||
{ startIndex: 3, scopes: '' },
|
||||
{ startIndex: 4, scopes: 'string.js' }
|
||||
]}]
|
||||
]);
|
||||
});
|
||||
|
||||
})
|
||||
29
tsconfig.json
Normal file
29
tsconfig.json
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "amd",
|
||||
"outDir": "out",
|
||||
"target": "es5"
|
||||
},
|
||||
"filesGlob": [
|
||||
"src/*.ts",
|
||||
"test/*.ts",
|
||||
"lib/*.d.ts",
|
||||
"node_modules/monaco-editor-core/monaco.d.ts"
|
||||
],
|
||||
"files": [
|
||||
"src/languageFeatures.ts",
|
||||
"src/mode.ts",
|
||||
"src/monaco.contribution.ts",
|
||||
"src/tokenization.ts",
|
||||
"src/typescript.ts",
|
||||
"src/worker.ts",
|
||||
"src/workerManager.ts",
|
||||
"test/assert.d.ts",
|
||||
"test/mocha.d.ts",
|
||||
"test/tokenization.test.ts",
|
||||
"lib/lib-es6-ts.d.ts",
|
||||
"lib/lib-ts.d.ts",
|
||||
"lib/typescriptServices.d.ts",
|
||||
"node_modules/monaco-editor-core/monaco.d.ts"
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue