add custom link provider for vscode.d.ts

This commit is contained in:
Johannes Rieken 2016-08-03 15:45:47 +02:00
parent 7ba701bbe0
commit 6f5b444f1c
7 changed files with 182 additions and 0 deletions

View file

@ -11,6 +11,7 @@ const extensions = [
'vscode-colorize-tests',
'json',
'configuration-editing',
'extension-editing',
'markdown',
'typescript',
'php',

View file

@ -0,0 +1,11 @@
{
"name": "extension-editing",
"version": "0.0.1",
"dependencies": {
"typescript": {
"version": "1.8.10",
"from": "typescript@>=1.8.10 <2.0.0",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-1.8.10.tgz"
}
}
}

View file

@ -0,0 +1,23 @@
{
"name": "extension-editing",
"version": "0.0.1",
"publisher": "vscode",
"engines": {
"vscode": "^1.4.0"
},
"categories": [
"Languages", "Other"
],
"activationEvents": [
"onLanguage:typescript"
],
"main": "./out/extension",
"scripts": {
"postinstall": "node ./postinstall",
"compile": "gulp compile-extension:extension-editing",
"watch": "gulp watch-extension:extension-editing"
},
"dependencies": {
"typescript": "^1.8.10"
}
}

View file

@ -0,0 +1,23 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
const fs = require('fs');
const path = require('path');
// delete unused typescript stuff
const root = path.dirname(require.resolve('typescript'));
for (let name of fs.readdirSync(root)) {
if (name !== 'typescript.d.ts' && name !== 'typescript.js') {
try {
fs.unlinkSync(path.join(root, name));
console.log(`removed '${path.join(root, name)}'`);
} catch (e) {
console.warn(e);
}
}
}

View file

@ -0,0 +1,103 @@
/*---------------------------------------------------------------------------------------------
* 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 vscode from 'vscode';
import * as ts from 'typescript';
export function activate(context: vscode.ExtensionContext) {
const registration = vscode.languages.registerDocumentLinkProvider({ language: 'typescript', pattern: '**/vscode.d.ts' }, _linkProvider);
context.subscriptions.push(registration);
}
const _linkProvider = new class implements vscode.DocumentLinkProvider {
private _cachedResult: { version: number; links: vscode.DocumentLink[] };
private _linkPattern = /[^!]\[.*?\]\(#(.*?)\)/g;
provideDocumentLinks(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.DocumentLink[] {
const {version} = document;
if (!this._cachedResult || this._cachedResult.version !== version) {
const links = this._computeDocumentLinks(document);
this._cachedResult = { version, links };
}
return this._cachedResult.links;
}
private _computeDocumentLinks(document: vscode.TextDocument): vscode.DocumentLink[] {
const results: vscode.DocumentLink[] = [];
const text = document.getText();
const lookUp = ast.createNamedNodeLookUp(text);
this._linkPattern.lastIndex = 0;
let match: RegExpMatchArray;
while ((match = this._linkPattern.exec(text))) {
const offset = lookUp(match[1]);
if (offset === -1) {
console.warn(match[1]);
continue;
}
const targetPos = document.positionAt(offset);
const linkEnd = document.positionAt(this._linkPattern.lastIndex - 1);
const linkStart = linkEnd.translate({ characterDelta: -(1 + match[1].length) });
results.push(new vscode.DocumentLink(
new vscode.Range(linkStart, linkEnd),
document.uri.with({ fragment: `${1 + targetPos.line}` })));
}
return results;
}
};
namespace ast {
export interface NamedNodeLookUp {
(dottedName: string): number;
}
export function createNamedNodeLookUp(str: string): NamedNodeLookUp {
const sourceFile = ts.createSourceFile('fake.d.ts', str, ts.ScriptTarget.Latest);
const identifiers: string[] = [];
const spans: number[] = [];
ts.forEachChild(sourceFile, function visit(node: ts.Node) {
const declIdent = (<ts.Declaration>node).name;
if (declIdent && declIdent.kind === ts.SyntaxKind.Identifier) {
identifiers.push((<ts.Identifier>declIdent).text);
spans.push(node.pos, node.end);
}
ts.forEachChild(node, visit);
});
return function (dottedName: string): number {
let start = -1;
let end = Number.MAX_VALUE;
for (const name of dottedName.split('.')) {
let idx: number;
while ((idx = identifiers.indexOf(name, idx + 1)) >= 0) {
let myStart = spans[2 * idx];
let myEnd = spans[2 * idx + 1];
if (myStart >= start && myEnd <= end) {
start = myStart;
end = myEnd;
break;
}
}
if (idx < 0) {
return -1;
}
}
return start;
};
}
}

View file

@ -0,0 +1,10 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../../../src/vs/vscode.d.ts'/>
/// <reference path='../../../../src/typings/mocha.d.ts'/>
/// <reference path='../../../../extensions/node.d.ts'/>
/// <reference path='../../../../extensions/lib.core.d.ts'/>
/// <reference path='../../../../extensions/declares.d.ts'/>

View file

@ -0,0 +1,11 @@
{
"compilerOptions": {
"noLib": true,
"target": "es5",
"module": "commonjs",
"outDir": "./out"
},
"exclude": [
"node_modules"
]
}