This commit is contained in:
Wenlu Wang 2021-08-13 16:41:26 +08:00
parent 39c9674e1d
commit 5632f5fed3
13 changed files with 31053 additions and 23817 deletions

6
package-lock.json generated
View file

@ -461,9 +461,9 @@
} }
}, },
"typescript": { "typescript": {
"version": "4.3.2", "version": "4.4.1-rc",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.1-rc.tgz",
"integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", "integrity": "sha512-SYdeKrJiOajqNTI+sweR70JET43Z567HFNo7DvvBof8J5/bt2cywy7VoWXqZyrsHEmQ9foraLtLr30mcfpfz9w==",
"dev": true "dev": true
}, },
"which": { "which": {

View file

@ -32,7 +32,7 @@
"pretty-quick": "^3.1.0", "pretty-quick": "^3.1.0",
"requirejs": "^2.3.6", "requirejs": "^2.3.6",
"terser": "^5.6.0", "terser": "^5.6.0",
"typescript": "^4.3.2" "typescript": "^4.4.1-rc"
}, },
"husky": { "husky": {
"hooks": { "hooks": {

View file

@ -242,7 +242,9 @@ export class DiagnosticsAdapter extends Adapter {
} }
}; };
this._disposables.push(editor.onDidCreateModel((model) => onModelAdd(<IInternalEditorModel>model))); this._disposables.push(
editor.onDidCreateModel((model) => onModelAdd(<IInternalEditorModel>model))
);
this._disposables.push(editor.onWillDisposeModel(onModelRemoved)); this._disposables.push(editor.onWillDisposeModel(onModelRemoved));
this._disposables.push( this._disposables.push(
editor.onDidChangeModelLanguage((event) => { editor.onDidChangeModelLanguage((event) => {
@ -574,9 +576,9 @@ function tagToString(tag: ts.JSDocTagInfo): string {
if (tag.name === 'param' && tag.text) { if (tag.name === 'param' && tag.text) {
const [paramName, ...rest] = tag.text; const [paramName, ...rest] = tag.text;
tagLabel += `\`${paramName.text}\``; tagLabel += `\`${paramName.text}\``;
if (rest.length > 0) tagLabel += `${rest.map(r => r.text).join(' ')}`; if (rest.length > 0) tagLabel += `${rest.map((r) => r.text).join(' ')}`;
} else if (Array.isArray(tag.text)) { } else if (Array.isArray(tag.text)) {
tagLabel += `${tag.text.map(r => r.text).join(' ')}`; tagLabel += `${tag.text.map((r) => r.text).join(' ')}`;
} else if (tag.text) { } else if (tag.text) {
tagLabel += `${tag.text}`; tagLabel += `${tag.text}`;
} }
@ -793,17 +795,15 @@ export class DefinitionAdapter extends Adapter {
range: this._textSpanToRange(refModel, entry.textSpan) range: this._textSpanToRange(refModel, entry.textSpan)
}); });
} else { } else {
const matchedLibFile = typescriptDefaults.getExtraLibs()[entry.fileName] const matchedLibFile = typescriptDefaults.getExtraLibs()[entry.fileName];
if (matchedLibFile) { if (matchedLibFile) {
const libModel = editor.createModel(matchedLibFile.content, 'typescript', uri); const libModel = editor.createModel(matchedLibFile.content, 'typescript', uri);
return { return {
uri: uri, uri: uri,
range: this._textSpanToRange(libModel, entry.textSpan) range: this._textSpanToRange(libModel, entry.textSpan)
};
} }
} }
}
} }
return result; return result;
} }
@ -894,7 +894,7 @@ export class OutlineAdapter extends Adapter implements languages.DocumentSymbolP
kind: <languages.SymbolKind>(outlineTypeTable[item.kind] || languages.SymbolKind.Variable), kind: <languages.SymbolKind>(outlineTypeTable[item.kind] || languages.SymbolKind.Variable),
range: this._textSpanToRange(model, item.spans[0]), range: this._textSpanToRange(model, item.spans[0]),
selectionRange: this._textSpanToRange(model, item.spans[0]), selectionRange: this._textSpanToRange(model, item.spans[0]),
tags: [], tags: []
}; };
if (containerLabel) result.containerName = containerLabel; if (containerLabel) result.containerName = containerLabel;
@ -1247,20 +1247,20 @@ export class InlayHintsAdapter extends Adapter implements languages.InlayHintsPr
const hints = await worker.provideInlayHints(fileName, start, end); const hints = await worker.provideInlayHints(fileName, start, end);
return hints.map(hint => { return hints.map((hint) => {
return { return {
...hint, ...hint,
position: model.getPositionAt(hint.position), position: model.getPositionAt(hint.position),
kind: this._convertHintKind(hint.kind) kind: this._convertHintKind(hint.kind)
} };
}) });
} }
private _convertHintKind (kind?: ts.InlayHintKind) { private _convertHintKind(kind?: ts.InlayHintKind) {
switch (kind) { switch (kind) {
case "Parameter": case 'Parameter':
return languages.InlayHintKind.Parameter; return languages.InlayHintKind.Parameter;
case "Type": case 'Type':
return languages.InlayHintKind.Type; return languages.InlayHintKind.Type;
default: default:
return languages.InlayHintKind.Other; return languages.InlayHintKind.Other;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -2,4 +2,4 @@
// **NOTE**: Do not edit directly! This file is generated using `npm run import-typescript` // **NOTE**: Do not edit directly! This file is generated using `npm run import-typescript`
// //
export const typescriptVersion = "4.3.2"; export const typescriptVersion = "4.4.1-rc";

View file

@ -169,6 +169,16 @@ export interface WorkerOptions {
customWorkerPath?: string; customWorkerPath?: string;
} }
interface InlayHintsOptions {
readonly includeInlayParameterNameHints?: 'none' | 'literals' | 'all';
readonly includeInlayParameterNameHintsWhenArgumentMatchesName?: boolean;
readonly includeInlayFunctionParameterTypeHints?: boolean;
readonly includeInlayVariableTypeHints?: boolean;
readonly includeInlayPropertyDeclarationTypeHints?: boolean;
readonly includeInlayFunctionLikeReturnTypeHints?: boolean;
readonly includeInlayEnumMemberValueHints?: boolean;
}
interface IExtraLib { interface IExtraLib {
content: string; content: string;
version: number; version: number;
@ -230,6 +240,8 @@ export interface LanguageServiceDefaults {
readonly workerOptions: WorkerOptions; readonly workerOptions: WorkerOptions;
readonly inlayHintsOptions: InlayHintsOptions;
/** /**
* Get the current extra libs registered with the language service. * Get the current extra libs registered with the language service.
*/ */
@ -458,11 +470,7 @@ export interface TypeScriptWorker {
* @param fileName * @param fileName
* @returns `Promise<typescript.InlayHint[]>` * @returns `Promise<typescript.InlayHint[]>`
*/ */
provideInlayHints( provideInlayHints(fileName: string, start: number, end: number): Promise<ReadonlyArray<any>>;
fileName: string,
start: number,
end: number,
): Promise<ReadonlyArray<any>>;
} }
// --- TypeScript configuration and defaults --------- // --- TypeScript configuration and defaults ---------
@ -478,11 +486,13 @@ class LanguageServiceDefaultsImpl implements LanguageServiceDefaults {
private _diagnosticsOptions!: DiagnosticsOptions; private _diagnosticsOptions!: DiagnosticsOptions;
private _workerOptions!: WorkerOptions; private _workerOptions!: WorkerOptions;
private _onDidExtraLibsChangeTimeout: number; private _onDidExtraLibsChangeTimeout: number;
private _inlayHintsOptions!: InlayHintsOptions;
constructor( constructor(
compilerOptions: CompilerOptions, compilerOptions: CompilerOptions,
diagnosticsOptions: DiagnosticsOptions, diagnosticsOptions: DiagnosticsOptions,
workerOptions: WorkerOptions workerOptions: WorkerOptions,
inlayHintsOptions: InlayHintsOptions
) { ) {
this._extraLibs = Object.create(null); this._extraLibs = Object.create(null);
this._removedExtraLibs = Object.create(null); this._removedExtraLibs = Object.create(null);
@ -490,6 +500,7 @@ class LanguageServiceDefaultsImpl implements LanguageServiceDefaults {
this.setCompilerOptions(compilerOptions); this.setCompilerOptions(compilerOptions);
this.setDiagnosticsOptions(diagnosticsOptions); this.setDiagnosticsOptions(diagnosticsOptions);
this.setWorkerOptions(workerOptions); this.setWorkerOptions(workerOptions);
this.setInlayHintsOptions(inlayHintsOptions);
this._onDidExtraLibsChangeTimeout = -1; this._onDidExtraLibsChangeTimeout = -1;
} }
@ -505,6 +516,10 @@ class LanguageServiceDefaultsImpl implements LanguageServiceDefaults {
return this._workerOptions; return this._workerOptions;
} }
get inlayHintsOptions(): InlayHintsOptions {
return this._inlayHintsOptions;
}
getExtraLibs(): IExtraLibs { getExtraLibs(): IExtraLibs {
return this._extraLibs; return this._extraLibs;
} }
@ -615,6 +630,11 @@ class LanguageServiceDefaultsImpl implements LanguageServiceDefaults {
this._onDidChange.fire(undefined); this._onDidChange.fire(undefined);
} }
setInlayHintsOptions(options: InlayHintsOptions): void {
this._inlayHintsOptions = options || Object.create(null);
this._onDidChange.fire(undefined);
}
setMaximumWorkerIdleTime(value: number): void {} setMaximumWorkerIdleTime(value: number): void {}
setEagerModelSync(value: boolean) { setEagerModelSync(value: boolean) {
@ -633,12 +653,14 @@ export const typescriptVersion: string = tsversion;
export const typescriptDefaults: LanguageServiceDefaults = new LanguageServiceDefaultsImpl( export const typescriptDefaults: LanguageServiceDefaults = new LanguageServiceDefaultsImpl(
{ allowNonTsExtensions: true, target: ScriptTarget.Latest }, { allowNonTsExtensions: true, target: ScriptTarget.Latest },
{ noSemanticValidation: false, noSyntaxValidation: false, onlyVisible: false }, { noSemanticValidation: false, noSyntaxValidation: false, onlyVisible: false },
{},
{} {}
); );
export const javascriptDefaults: LanguageServiceDefaults = new LanguageServiceDefaultsImpl( export const javascriptDefaults: LanguageServiceDefaults = new LanguageServiceDefaultsImpl(
{ allowNonTsExtensions: true, allowJs: true, target: ScriptTarget.Latest }, { allowNonTsExtensions: true, allowJs: true, target: ScriptTarget.Latest },
{ noSemanticValidation: true, noSyntaxValidation: false, onlyVisible: false }, { noSemanticValidation: true, noSyntaxValidation: false, onlyVisible: false },
{},
{} {}
); );

View file

@ -39,11 +39,13 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, ITypeScriptWork
private _extraLibs: IExtraLibs = Object.create(null); private _extraLibs: IExtraLibs = Object.create(null);
private _languageService = ts.createLanguageService(this); private _languageService = ts.createLanguageService(this);
private _compilerOptions: ts.CompilerOptions; private _compilerOptions: ts.CompilerOptions;
private _inlayHintsOptions?: ts.InlayHintsOptions;
constructor(ctx: worker.IWorkerContext, createData: ICreateData) { constructor(ctx: worker.IWorkerContext, createData: ICreateData) {
this._ctx = ctx; this._ctx = ctx;
this._compilerOptions = createData.compilerOptions; this._compilerOptions = createData.compilerOptions;
this._extraLibs = createData.extraLibs; this._extraLibs = createData.extraLibs;
this._inlayHintsOptions = createData.inlayHintsOptions;
} }
// --- language service host --------------- // --- language service host ---------------
@ -191,7 +193,9 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, ITypeScriptWork
diagnostic.relatedInformation = []; diagnostic.relatedInformation = [];
for (const tsRelatedDiagnostic of tsDiagnostic.relatedInformation) { for (const tsRelatedDiagnostic of tsDiagnostic.relatedInformation) {
const relatedDiagnostic: DiagnosticRelatedInformation = { ...tsRelatedDiagnostic }; const relatedDiagnostic: DiagnosticRelatedInformation = { ...tsRelatedDiagnostic };
relatedDiagnostic.file = relatedDiagnostic.file ? { fileName: relatedDiagnostic.file.fileName } : undefined relatedDiagnostic.file = relatedDiagnostic.file
? { fileName: relatedDiagnostic.file.fileName }
: undefined;
diagnostic.relatedInformation.push(relatedDiagnostic); diagnostic.relatedInformation.push(relatedDiagnostic);
} }
} }
@ -416,24 +420,22 @@ export class TypeScriptWorker implements ts.LanguageServiceHost, ITypeScriptWork
this._extraLibs = extraLibs; this._extraLibs = extraLibs;
} }
async provideInlayHints(fileName: string, start: number, end: number): Promise<readonly ts.InlayHint[]> { async provideInlayHints(
fileName: string,
start: number,
end: number
): Promise<readonly ts.InlayHint[]> {
if (fileNameIsLib(fileName)) { if (fileNameIsLib(fileName)) {
return []; return [];
} }
const preferences: ts.InlayHintsOptions = { const preferences: ts.InlayHintsOptions = this._inlayHintsOptions ?? {};
includeInlayParameterNameHints: "all"
};
const span: ts.TextSpan = { const span: ts.TextSpan = {
start, start,
length: end - start length: end - start
} };
try { try {
return this._languageService.provideInlayHints( return this._languageService.provideInlayHints(fileName, span, preferences);
fileName,
span,
preferences
);
} catch { } catch {
return []; return [];
} }
@ -444,6 +446,7 @@ export interface ICreateData {
compilerOptions: ts.CompilerOptions; compilerOptions: ts.CompilerOptions;
extraLibs: IExtraLibs; extraLibs: IExtraLibs;
customWorkerPath?: string; customWorkerPath?: string;
inlayHintsOptions?: ts.InlayHintsOptions;
} }
/** The shape of the factory */ /** The shape of the factory */

View file

@ -71,7 +71,8 @@ export class WorkerManager {
createData: { createData: {
compilerOptions: this._defaults.getCompilerOptions(), compilerOptions: this._defaults.getCompilerOptions(),
extraLibs: this._defaults.getExtraLibs(), extraLibs: this._defaults.getExtraLibs(),
customWorkerPath: this._defaults.workerOptions.customWorkerPath customWorkerPath: this._defaults.workerOptions.customWorkerPath,
inlayHintsOptions: this._defaults.inlayHintsOptions
} }
}); });

219
test/inlayHints.html Normal file
View file

@ -0,0 +1,219 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link
rel="stylesheet"
data-name="vs/editor/editor.main"
href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css"
/>
</head>
<body>
<h2>Monaco Editor TypeScript test page</h2>
<button id="resetBtn">Reset Sample</button>
<div id="container" style="width: 800px; height: 600px; border: 1px solid grey"></div>
<h3>Inlay Hints options</h3>
<textarea style="font-family: monospace" id="inlayHintsOpts" cols="60" rows="30"></textarea
><br />
<button id="updateInlayHintsOptionsBtn">Update Inaly Hints options</button>
<script>
const paths = {
'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
'vs/language/typescript/fillers/monaco-editor-core':
'../out/amd/fillers/monaco-editor-core-amd',
'vs/language/typescript': '../out/amd',
vs: '../node_modules/monaco-editor-core/dev/vs'
};
if (document.location.protocol === 'http:') {
// Add support for running local http server
let testIndex = document.location.pathname.indexOf('/test/');
if (testIndex !== -1) {
let prefix = document.location.pathname.substr(0, testIndex);
paths['vs/language/typescript'] = prefix + '/out/amd';
}
}
self.require = {
paths: paths
};
</script>
<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script>
<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.nls.js"></script>
<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.js"></script>
<script>
function getDefaultCode() {
return [
'/* Game of Life',
' * Implemented in TypeScript',
' * To learn more about TypeScript, please visit http://www.typescriptlang.org/',
' */',
'',
'module Conway {',
'',
' export class Cell {',
' public row: number;',
' public col: number;',
' public live: boolean;',
'',
' constructor(row: number, col: number, live: boolean) {',
' this.row = row;',
' this.col = col;',
' this.live = live',
' }',
' }',
'',
' export class GameOfLife {',
' private gridSize: number;',
' private canvasSize: number;',
' private lineColor: string;',
' private liveColor: string;',
' private deadColor: string;',
' private initialLifeProbability: number;',
' private animationRate: number;',
' private cellSize: number;',
' private context: CanvasRenderingContext2D;',
' private world;',
'',
'',
' constructor() {',
' this.gridSize = 50;',
' this.canvasSize = 600;',
" this.lineColor = '#cdcdcd';",
" this.liveColor = '#666';",
" this.deadColor = '#eee';",
' this.initialLifeProbability = 0.5;',
' this.animationRate = 60;',
' this.cellSize = 0;',
' this.world = this.createWorld();',
' this.circleOfLife();',
' }',
'',
' public createWorld() {',
' return this.travelWorld( (cell : Cell) => {',
' cell.live = Math.random() < this.initialLifeProbability;',
' return cell;',
' });',
' }',
'',
' public circleOfLife() : void {',
' this.world = this.travelWorld( (cell: Cell) => {',
' cell = this.world[cell.row][cell.col];',
' this.draw(cell);',
' return this.resolveNextGeneration(cell);',
' });',
' setTimeout( () => {this.circleOfLife()}, this.animationRate);',
' }',
'',
' public resolveNextGeneration(cell : Cell) {',
' var count = this.countNeighbors(cell);',
' var newCell = new Cell(cell.row, cell.col, cell.live);',
' if(count < 2 || count > 3) newCell.live = false;',
' else if(count == 3) newCell.live = true;',
' return newCell;',
' }',
'',
' public countNeighbors(cell : Cell) {',
' var neighbors = 0;',
' for(var row = -1; row <=1; row++) {',
' for(var col = -1; col <= 1; col++) {',
' if(row == 0 && col == 0) continue;',
' if(this.isAlive(cell.row + row, cell.col + col)) {',
' neighbors++;',
' }',
' }',
' }',
' return neighbors;',
' }',
'',
' public isAlive(row : number, col : number) {',
' if(row < 0 || col < 0 || row >= this.gridSize || col >= this.gridSize) return false;',
' return this.world[row][col].live;',
' }',
'',
' public travelWorld(callback) {',
' var result = [];',
' for(var row = 0; row < this.gridSize; row++) {',
' var rowData = [];',
' for(var col = 0; col < this.gridSize; col++) {',
' rowData.push(callback(new Cell(row, col, false)));',
' }',
' result.push(rowData);',
' }',
' return result;',
' }',
'',
' public draw(cell : Cell) {',
' if(this.context == null) this.context = this.createDrawingContext();',
' if(this.cellSize == 0) this.cellSize = this.canvasSize/this.gridSize;',
'',
' this.context.strokeStyle = this.lineColor;',
' this.context.strokeRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize);',
' this.context.fillStyle = cell.live ? this.liveColor : this.deadColor;',
' this.context.fillRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize);',
' }',
'',
' public createDrawingContext() {',
" var canvas = <HTMLCanvasElement> document.getElementById('conway-canvas');",
' if(canvas == null) {',
" canvas = document.createElement('canvas');",
" canvas.id = 'conway-canvas';",
' canvas.width = this.canvasSize;',
' canvas.height = this.canvasSize;',
' document.body.appendChild(canvas);',
' }',
" return canvas.getContext('2d');",
' }',
' }',
'}',
'',
'var game = new Conway.GameOfLife();'
].join('\n');
}
function getDefaultInlayHintsOpts() {
return {
includeInlayParameterNameHints: 'all',
includeInlayParameterNameHintsWhenArgumentMatchesName: true,
includeInlayFunctionParameterTypeHints: true,
includeInlayVariableTypeHints: true,
includeInlayPropertyDeclarationTypeHints: true,
includeInlayFunctionLikeReturnTypeHints: true,
includeInlayEnumMemberValueHints: true
};
}
require([
'vs/basic-languages/monaco.contribution',
'vs/language/typescript/monaco.contribution'
], () => {
const editor = monaco.editor.create(document.getElementById('container'), {
value: localStorage.getItem('code') || getDefaultCode(),
language: 'typescript',
lightbulb: { enabled: true }
});
editor.onDidChangeModelContent(() => {
const code = editor.getModel().getValue();
localStorage.setItem('code', code);
});
document.getElementById('resetBtn').onclick = () => {
editor.setValue(getDefaultCode());
};
const optsString =
localStorage.getItem('inlay-hints-opts') ||
JSON.stringify(getDefaultInlayHintsOpts(), null, 4);
document.getElementById('inlayHintsOpts').textContent = optsString;
monaco.languages.typescript.typescriptDefaults.setInlayHintsOptions(JSON.parse(optsString));
document.getElementById('updateInlayHintsOptionsBtn').onclick = () => {
const newOpts = document.getElementById('inlayHintsOpts').value;
monaco.languages.typescript.typescriptDefaults.setInlayHintsOptions(JSON.parse(newOpts));
localStorage.setItem('inlay-hints-opts', newOpts);
};
});
</script>
</body>
</html>