Skip to content

Commit

Permalink
update document sample with sample for links
Browse files Browse the repository at this point in the history
  • Loading branch information
jrieken committed Jul 29, 2016
1 parent fa22df9 commit 6e6a906
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 39 deletions.
2 changes: 1 addition & 1 deletion contentprovider-sample/README.md
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion contentprovider-sample/package.json
Expand Up @@ -12,7 +12,7 @@
"url": "https://github.com/Microsoft/vscode-extension-samples/issues"
},
"engines": {
"vscode": "^1.0.0"
"vscode": "^1.4.0"
},
"categories": [
"Other"
Expand Down
Binary file modified contentprovider-sample/preview.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 10 additions & 6 deletions contentprovider-sample/src/extension.ts
Expand Up @@ -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
Expand All @@ -21,8 +25,8 @@ export function activate(context: ExtensionContext) {
});

context.subscriptions.push(
contentProvider,
provider,
commandRegistration,
providerRegistration
providerRegistrations
);
}
Expand Up @@ -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';

Expand All @@ -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() {
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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] {
Expand Down
23 changes: 12 additions & 11 deletions contentprovider-sample/src/referencesDocument.ts
Expand Up @@ -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>) {
Expand All @@ -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> {
Expand Down Expand Up @@ -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]);
}

Expand All @@ -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 {
Expand Down

0 comments on commit 6e6a906

Please sign in to comment.