Document Selectors
Extensions can filter their features based on document selectors by language, file type, and location. This topic discusses document selectors, document schemes, and what extensions authors should be aware about.
Text documents not on disk
Not all text documents are stored on disk, for example, newly created documents. Unless specified, a document selector applies toall document types. Use theDocumentFilterscheme property to narrow down on certain schemes, for example{ scheme: 'file', language: 'typescript' } for TypeScript files that are stored on disk.
Document selectors
The Visual Studio Code extension API combines language-specific features, like IntelliSense, with document selectors through theDocumentSelector type. They are an easy mechanism to narrow down functionality to a specific language.
The snippet below registers aHoverProvider for TypeScript files and the document selector is thetypescript language identifier string.
vscode.languages.registerHoverProvider('typescript', { provideHover(doc:vscode.TextDocument) { return new vscode.Hover('For *all* TypeScript documents.'); }});A document selector can be more than just a language identifier and more complex selectors can use aDocumentFilter to filter based on thescheme and file location through apattern path glob-pattern:
vscode.languages.registerHoverProvider( {pattern: '**/test/**' }, { provideHover(doc:vscode.TextDocument) { return new vscode.Hover('For documents inside `test`-folders only'); } });The next snippet uses thescheme filter and combines it with a language identifier. Theuntitled scheme is for new files that have not yet been saved to disk.
vscode.languages.registerHoverProvider( {scheme: 'untitled',language: 'typescript' }, { provideHover(doc:vscode.TextDocument) { return new vscode.Hover('For new, unsaved TypeScript documents only'); } });Document scheme
Thescheme of a document is often overlooked but is an important piece of information. Most documents are saved on disk and extension authors typically assume they are working with a file on disk. For example with a simpletypescript selector, the assumption isTypeScript files on disk. However, there are scenarios where that assumption is too lax and a more explicit selector like{ scheme: 'file', language: 'typescript' } should be used.
The importance of this comes into play when features rely on reading/writing files from/to disk. Check out the snippet below:
// 👎 too laxvscode.languages.registerHoverProvider('typescript', { provideHover(doc:vscode.TextDocument) { const {size } =fs.statSync(doc.uri.fsPath);// ⚠️ what about 'untitled:/Untitled1.ts' or others? return new vscode.Hover(`Size in bytes is${size}`); }});The hover provider above wants to display the size of a document on disk but it fails to check whether the document is actually stored on disk. For example, it could be newly created and not yet saved. The correct way would be to tell VS Code that the provider can only work with files on disk.
// 👍 only works with files on diskvscode.languages.registerHoverProvider( {scheme: 'file',language: 'typescript' }, { provideHover(doc:vscode.TextDocument) { const {size } =fs.statSync(doc.uri.fsPath); return new vscode.Hover(`Size in bytes is${size}`); } });Summary
Documents are usually stored on the file system, but not always: there are untitled documents, cached documents that Git uses, documents from remote sources like FTP, and so forth. If your feature relies on disk access, make sure to use a document selector with thefile scheme.
Next steps
To learn more about VS Code extensibility model, try these topics:
- Extension Manifest File - VS Code package.json extension manifest file reference
- Contribution Points - VS Code contribution points reference