Content Provider Tutorial for VSCode
fake this content!
First and foremost this tutorial is about Visual Studio Code
and has nothing to do with Visual Studio
. Additionally, this tutorial is mainly geared towards developers writing extensions for Visual Studio Code (VSCode). Interested? Then let's move forward.
Lately, I have been doing quite a bit of TypeScript and dealing with Visual Studio Code API for authoring an extension. One of the plugins for which I contribute had a peculiar requirement to display a read-only
document in the editor. By using the API!
One would think it should be a very straight forward process, right? Well it is once you get a hang of how exactly to accomplish it using the API. Meet the TextDocumentContentProvider. Say what?
Yeah, ContentProviders allow you to add read only documents to VSCode editor. How? Let's take it step-by-step.
- Understand URI(s)
- Create a custom URI-scheme
- Create a ContentProvider
- Register URI scheme and a ContentProvider
- Display read-only content
URI (Uniform Resource Identifier)
Straight from the Wiki page: a Uniform Resource Identifier is a string of characters used to identify a resource. URI(s) have a scheme, authority, path, an optional query and an optional fragment. Here is a sample URI.
file://ritesh@line89.com:123/path/to/fake/file?key=myfile#fragid1
Let's quickly dissect this URI and understand how it is formed.
file: - is a scheme
ritesh@line89.com:123 - is authority
/path/to/fake/file - is a path
?key=myfile - is a query
fragid1 - is a fragment
Why am I showing this ? Well, it is a must to understand how URI(s) are formed before moving forward with the ContentProvider(s).
Create a custom URI scheme
To open a read-only document via VSCode API, one of the requirements is to create a custom URI scheme. We all know there are pre-defined schemes like http:, file:, untitled: and so on. For our purpose let's create a URI scheme called: settings-preview:
.
In other words any time I wish to open a read-only settings I will use this URI scheme. Rest of the URI can be as fake as you want : as long as it resolves to a valid URI.
For this tutorial we will use the URI below.
settings-preview://my-extension/fake/path/to/settings
Next, let's create a ContentProvider for our extension. We will call it a SettingsProvider
since we wish to load read-only settings in the editor.
Create a ContentProvider
ContentProvider is nothing but merely a class that will extract the text from a resource of your choice. And a resource could be another text file, JSON document or a database. Your call.
To keep things simple, we will use a JSON document somewhere on the file system. Our ContentProvider will read this JSON file and return a string to be displayed in the editor. Main point to remember here is: Our SettingsProvider is implementing TextDocumentContentProvider interface.
'use strict';
import * as vscode from 'vscode';
const path = require('path');
const cjson = require('cjson');
const fs = require('fs');
export default class SettingsProvider implements TextDocumentContentProvider {
/**
*
* @param {vscode.Uri} uri - a fake uri
* @returns {string} - settings read from the JSON file
**/
public provideTextDocumentContent (uri : Uri) : string {
let settingsFilePath = '/path/to/settings/file/settings.json';
let returnString : string;
// read settings file
if (fs.existsSync (settingsFilePath)) {
returnString = cjson.load(setttingsFilePath);
}
// return JSON object as a string
return JSON.stringify(returnString, null, 4) || ''; // prettify and return
}
}
A very simple ContentProvider class. Since our class is implementing TextDocumentContentProvider we must provide an implementation for provideTextDocumentContent
. It is used to read and process the content.
Next we will register the URI scheme and a ContentProvider.
Register URI scheme and a ContentProvider
In your extension.ts
file register the URI scheme as below.
import {workspace, window, Disposable, ExtensionContext} from 'vscode';
import SettingsProvider from './SettingsProvider';
export function activate (context : ExtensionContext) {
// instantiate SettingsProvider
const settingsProvider = new SettingsProvider();
// register provider and a scheme
const registration = Disposable.from (
workspace.registerTextDocumentContentProvider ('settings-preview', settingsProvider);
);
// push it to context subscriptions
context.subscriptions.push (
registration
);
Done, our custom URI scheme and a ContentProvider is now registered with the extension.
Display read-only content
And now all left is to invoke the ContentProvider and display read-only content in the editor. ContentProvider is invoked when a request is made with the settings-preview
URI. Because our URI scheme is registered with the extension, it will automatically invoke the ContentProvider registered with the scheme and provide the content.
One more time, here is the URI we created above.
settings-preview://my-extension/fake/path/to/settings
Let's create a function to open a text document with this URI.
export default function (context : ExtensionContext) : Thenable <TextEditor> {
return new Promise <TextEditor> ((resolve, reject) => {
let settingsUri = 'settings-preview://my-extension/fake/path/to/settings';
// open a fake document (content served from the SettingsProvider)
workspace.openTextDocument(Uri.parse(settingsUri))
.then (doc => window.showTextDocument(doc)
.then (editor => {
if (editor) {
resolve (editor);
} else {
resolve (null);
}
}))
});
}
And voila! That's it!
If done correctly, the VSCode editor should display read-only settings from a JSON document.
Cheers!
Hi, I am Ritesh Patel. I live in a beautiful town surrounded by the mountains. C&O Canal is few miles away. State parks are only a distance away & bike trails galore. It is home sweet home Frederick, MD. A passionate developer. Love to cook. Enjoy playing "Bollywood Tunes" on my harmonica. Apart from that just a normal guy.