Permalink
Browse files

update document sample with sample for links

  • Loading branch information...
jrieken committed Jul 29, 2016
1 parent fa22df9 commit 6e6a906dbb2d3a6f8ae5163e33cb935ed3af13b8
@@ -16,7 +16,7 @@ It is not intended as a product quality extension.
- The extension implements and registers a [`TextDocumentContentProvider`](http://code.visualstudio.com/docs/extensionAPI/vscode-api#TextDocumentContentProvider) for a particular URI scheme.
- The content provider uses the [`vscode.executeReferenceProvider`](http://code.visualstudio.com/docs/extensionAPI/vscode-api-commands)-API command to delegate searching for references to the language extensions, like TypeScript, vscode-go, or C#
- The generated document initially contains a caption only and incrementally updates as each reference location is resolved.
- The content provider uses the decoration API to highlight matches inside the generated document
- Add links for each result in the virtual document pointing to the reference.
- Add an entry to editor context menu via `package.json`
# How to run locally
@@ -12,7 +12,7 @@
"url": "https://github.com/Microsoft/vscode-extension-samples/issues"
},
"engines": {
"vscode": "^1.0.0"
"vscode": "^1.4.0"
},
"categories": [
"Other"
Binary file not shown.
@@ -3,15 +3,19 @@
*--------------------------------------------------------*/
'use strict';
import {workspace, window, commands, ExtensionContext} from 'vscode';
import ContentProvider, {encodeLocation} from './contentProvider';
import {workspace, languages, window, commands, ExtensionContext, Disposable} from 'vscode';
import ContentProvider, {encodeLocation} from './provider';
export function activate(context: ExtensionContext) {
const contentProvider = new ContentProvider();
const provider = new ContentProvider();
// register content provider for scheme `references`
const providerRegistration = workspace.registerTextDocumentContentProvider(ContentProvider.scheme, contentProvider);
// register document link provider for scheme `references`
const providerRegistrations = Disposable.from(
workspace.registerTextDocumentContentProvider(ContentProvider.scheme, provider),
languages.registerDocumentLinkProvider({ scheme: ContentProvider.scheme }, provider)
);
// register command that crafts an uri with the `references` scheme,
// open the dynamic document, and shows it in the next editor
@@ -21,8 +25,8 @@ export function activate(context: ExtensionContext) {
});
context.subscriptions.push(
contentProvider,
provider,
commandRegistration,
providerRegistration
providerRegistrations
);
}
@@ -6,7 +6,7 @@
import * as vscode from 'vscode';
import ReferencesDocument from './referencesDocument';
export default class ContentProvider implements vscode.TextDocumentContentProvider {
export default class Provider implements vscode.TextDocumentContentProvider, vscode.DocumentLinkProvider {
static scheme = 'references';
@@ -19,11 +19,7 @@ export default class ContentProvider implements vscode.TextDocumentContentProvid
// Listen to the following events:
// * closeTextDocument - which means we must clear the corresponding model object - `ReferencesDocument`
// * changeActiveEditor - do decorate with references information
this._subscriptions = vscode.Disposable.from(
vscode.workspace.onDidCloseTextDocument(doc => this._documents.delete(doc.uri.toString())),
vscode.window.onDidChangeActiveTextEditor(this._decorateEditor, this)
);
this._subscriptions = vscode.workspace.onDidCloseTextDocument(doc => this._documents.delete(doc.uri.toString()));
}
dispose() {
@@ -63,7 +59,7 @@ export default class ContentProvider implements vscode.TextDocumentContentProvid
// sort by locations and shuffle to begin from target resource
let idx = 0;
locations.sort(ContentProvider._compareLocations).find((loc, i) => loc.uri.toString() === target.toString() && (idx = i) && true);
locations.sort(Provider._compareLocations).find((loc, i) => loc.uri.toString() === target.toString() && (idx = i) && true);
locations.push(...locations.splice(0, idx));
// create document and return its early state
@@ -73,18 +69,6 @@ export default class ContentProvider implements vscode.TextDocumentContentProvid
});
}
private _decorateEditor(editor: vscode.TextEditor) {
// When an editor opens, check if it shows a `location` document
// and decorate the actual references
if (!editor || !vscode.languages.match('locations', editor.document)) {
return;
}
let doc = this._documents.get(editor.document.uri.toString());
if (doc) {
doc.join().then(() => editor.setDecorations(this._editorDecoration, doc.ranges));
}
}
private static _compareLocations(a: vscode.Location, b: vscode.Location): number {
if (a.uri.toString() < b.uri.toString()) {
return -1;
@@ -94,13 +78,23 @@ export default class ContentProvider implements vscode.TextDocumentContentProvid
return a.range.start.compareTo(b.range.start)
}
}
provideDocumentLinks(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.DocumentLink[] {
// While building the virtual document we have already created the links.
// Those are composed from the range inside the document and a target uri
// to which they point
const doc = this._documents.get(document.uri.toString());
if (doc) {
return doc.links;
}
}
}
let seq = 0;
export function encodeLocation(uri: vscode.Uri, pos: vscode.Position): vscode.Uri {
const query = JSON.stringify([uri.toString(), pos.line, pos.character]);
return vscode.Uri.parse(`${ContentProvider.scheme}:References.locations?${query}#${seq++}`);
return vscode.Uri.parse(`${Provider.scheme}:References.locations?${query}#${seq++}`);
}
export function decodeLocation(uri: vscode.Uri): [vscode.Uri, vscode.Position] {
@@ -12,7 +12,7 @@ export default class ReferencesDocument {
private _locations: vscode.Location[];
private _lines: string[];
private _ranges: vscode.Range[];
private _links: vscode.DocumentLink[];
private _join: Thenable<this>;
constructor(uri: vscode.Uri, locations: vscode.Location[], emitter: vscode.EventEmitter<vscode.Uri>) {
@@ -25,16 +25,16 @@ export default class ReferencesDocument {
// Start with printing a header and start resolving
this._lines = [`Found ${this._locations.length} references`];
this._ranges = [];
this._links = [];
this._join = this._populate();
}
get value() {
return this._lines.join('\n');
}
get ranges() {
return this._ranges;
get links() {
return this._links;
}
join(): Thenable<this> {
@@ -98,7 +98,7 @@ export default class ReferencesDocument {
for (let i = 0; i < ranges.length; i++) {
const {start: {line}} = ranges[i];
this._appendLeading(doc, line, ranges[i - 1]);
this._appendMatch(doc, line, ranges[i]);
this._appendMatch(doc, line, ranges[i], uri);
this._appendTrailing(doc, line, ranges[i + 1]);
}
@@ -115,17 +115,18 @@ export default class ReferencesDocument {
}
}
private _appendMatch(doc: vscode.TextDocument, line:number, match: vscode.Range) {
private _appendMatch(doc: vscode.TextDocument, line:number, match: vscode.Range, target: vscode.Uri) {
const text = doc.lineAt(line).text;
const preamble = ` ${line + 1}: `;
// Append line, use new length of lines-array as line number
// for decoration in the document (should really be a link)
// for a link that point to the reference
const len = this._lines.push(preamble + text);
this._ranges.push(new vscode.Range(
len - 1, preamble.length + match.start.character,
len - 1, preamble.length + match.end.character)
);
// Create a document link that will reveal the reference
const linkRange = new vscode.Range(len - 1, preamble.length + match.start.character, len - 1, preamble.length + match.end.character);
const linkTarget = target.with({ fragment: String(1 + match.start.line) });
this._links.push(new vscode.DocumentLink(linkRange, linkTarget));
}
private _appendTrailing(doc: vscode.TextDocument, line: number, next: vscode.Range): void {

0 comments on commit 6e6a906

Please sign in to comment.