mirror of
https://github.com/microsoft/monaco-editor.git
synced 2025-12-22 11:35:40 +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
|
# Monaco TypeScript
|
||||||
TypeScript/JavaScript language support for the Monaco Editor
|
|
||||||
|
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