API
=== commands
use
programmatically execute a command
links:
-
builtin commands: https://code.visualstudio.com/api/references/commands
-
eg: add a comment
import * as vscode from "vscode";
function commentLine() {
vscode.commands.executeCommand("editor.action.addCommentLine");
}
- eg: pass argument and work with result
import * as vscode from "vscode";
async function printDefinitionsForActiveEditor() {
const activeEditor = vscode.window.activeTextEditor;
if (!activeEditor) {
return;
}
const definitions = await vscode.commands.executeCommand<vscode.Location[]>(
"vscode.executeDefinitionProvider",
activeEditor.document.uri,
activeEditor.selection.active
);
for (const definition of definitions) {
console.log(definition);
}
}
=== extensions
related
- ExtensionContext
- EnvironmentVariableCollection
=== languages
registerDefinitionProvider
link: https://code.visualstudio.com/api/references/vscode-api#languages.registerDefinitionProvider
- params
- selector: DocumentSelector
- A selector that defines the documents this provider is applicable to.
- provider: DefinitionProvider
- A definition provider.
- selector: DocumentSelector
=== patterns
Dispose pattern
links:
- https://en.wikipedia.org/wiki/Dispose_pattern
- https://code.visualstudio.com/api/references/vscode-api#disposables
-
a resource is held by an object, and released by calling a method – usually called
close, dispose, free, release
-
Many languages offer language constructs to avoid having to call the dispose method explicitly in common situations
-
motivation
- Resources are typically represented by handles (abstract references)
- used to communicate with an external system that provides the resource
- eg: files are provided by the operating system (specifically the file system), which in many systems represents files with a file descriptor (an integer representing the file).
- These handles can be used directly, by storing the value in a variable and passing it as an argument to functions that use the resource
- frequently useful to abstract from the handle itself (for example, if different operating systems represent files differently), and to store additional auxiliary data with the handle, so handles can be stored as a field in a record, along with other data
- eg: in C file input/output, files are represented by objects of the FILE type
- which stores an (operating system) handle to the file (such as a file descriptor), together with auxiliary information like I/O mode (reading, writing) and position in the stream
- These objects are created by calling fopen (in object-oriented terms, a factory), which acquires the resource and returns a pointer to it
- the resource is released by calling fclose on a pointer to the FILE object[1]. In code
- eg: in C file input/output, files are represented by objects of the FILE type
- Resources are typically represented by handles (abstract references)
FILE *f = fopen(filename, mode);
// Do something with f.
fclose(f);
- fundamental problem that the dispose pattern aims to solve is that resources are expensive (for example, there may be a limit on the number of open files), and thus should be released promptly
- some finalization work is often needed, particularly for I/O, such as flushing buffers to ensure that all data is actually written.
- If a resource is unlimited or effectively unlimited, and no explicit finalization is necessary, it is not important to release it, and in fact short-lived programs often do not explicitly release resources
- Explicit disposal means that resource finalization and release is deterministic and prompt: the dispose method does not complete until these are done.
- alternative to requiring explicit disposal is to tie resource management to object lifetime
- This approach is known as the Resource Acquisition Is Initialization (RAII) idiom
issues
early exit
-
key problem with the dispose pattern is that if the dispose method is not called, the resource is leaked
-
A common cause of this is early exit from a function, due to an early return or exception.
-
to solve early exit, languages have constructs that auto-release
-
eg: python
with
statement
with resource_context_manager() as resource:
# Perform actions with the resource.
...
## Perform other actions where the resource is guaranteed to be deallocated.
...
class invariance
-
A fundamental problem is that having a resource is no longer a class invariant (the resource is held from object creation until it is disposed, but the object is still live at this point), so the resource may not be available when the object tries to use it, for example trying to read from a closed file
-
all methods on the object that use the resource potentially fail, concretely usually by returning an error or raising an exception
-
A standard way to implement this is to add a boolean field to the object, called disposed, which is set to true by dispose, and checked by a guard clause to all methods (that use the resource), raising an exception (such as ObjectDisposedException in .NET) if the object has been disposed.[5]
-
Further, it is possible to call dispose on an object more than once
- preferable for dispose to be idempotent
- easily implemented by using the same boolean disposed field and checking it in a guard clause at the start of dispose
Events
- Calls to subscribe return a Disposable which removes the event listener upon dispose
var listener = function (event) {
console.log("It happened", event);
};
// start listening
var subscription = fsWatcher.onDidDelete(listener);
// do more stuff
subscription.dispose(); // stop listening
- Names of events follow the
on[Will|Did]VerbNoun?
pattern- The name signals if the event is going to happen (onWill) or already happened (onDid), what happened (verb), and the context (noun) unless obvious from the context.
- An example from the VS Code API is window.onDidChangeActiveTextEditor which is an event fired when the active text editor (noun) has been (onDid) changed (verb).
=== bucket
Welcome View Content API
- original issue: https://github.com/microsoft/vscode/issues/89080
- eg: https://code.visualstudio.com/api/extension-guides/tree-view#welcome-content
--- Others
events
onDidChange
release: 1.27
A new event extensions.onDidChange
was added which fires when the extensions.all
array changes. This can happen when extensions are installed, uninstalled, enabled, or disabled. See the No reload on extension install section.
/**
* An event which fires when `extensions.all` changes. This can happen when extensions are
* installed, uninstalled, enabled or disabled.
*/
export const onDidChange: Event<void>;
onStartupFinished
- similar to the already existing * activation event. The new onStartupFinished activation event should be used when an extension wishes to be activated sometime soon after VS Code startup, but not as part of the startup.
=== Bucket
=== Utils
Terminal
updates
The Terminal
object has a new creationOptions
property that can be used by extensions to identify how the terminal was created.
vscode.Uri
file
File path casing
We have fixed a couple of bugs with how VS Code handles paths and URIs on case-insensitive file systems. Before this release, paths with different casing would not open the same document but separate, disconnected documents. That behavior often caused confusion and sometimes data loss.
However, in fixing these bugs, the behavior of the openTextDocument
function has changed. The function can now return a document with a URI with different casing than the URI that was passed in. This means extensions should use TextDocument#uri as the source of truth, not the URI that they request it with.
The sample below illustrates the new behavior:
// case-insensitive file system
const uriA = vscode.Uri.file("/foo/bar.code");
const docA = await vscode.workspace.openTextDocument(uriA);
const uriB = vscode.Uri.file("/foo/BAR.code");
const docB = await vscode.workspace.openTextDocument(uriB);
assert.ok(docA === docB); // same document
assert.ok(docB.uri.toString() === uriA.toString()); // uriA is used, NOT uriB
assert.ok(docB.uri.toString() !== uriB.toString());
joinPath
We have added a vscode.Uri.joinPath
utility. It is a factory function that creates new URIs by joining path segments with an existing URI. Think of this as Node.js' path.join
utility but for URIs.
- NOTE: s/extensionUri/extensionPath
const fileUri = vscode.Uri.joinPath(context.extensionUri, "./file.png");
const bytes = await vscode.workspace.fs.readFile(fileUri);
vscode.env
vscode.env.openExternal
we have added a new API vscode.env.openExternal
. It expects a URL and can be used to open website-links, mail-links, or application-url-handler. Also, file URLs are accepted to open them in their default app, like a PDF file.
// open default browser
await vscode.env.openExternal(
vscode.Uri.parse("https://github.com/Microsoft/vscode/issues/66741")
);
filesystem
We have added FileSystemError#code, which is a string identifying the error. When a file system error is created through any of its factory functions, then code
is the name of that function, for example FileSystemError.FileNotFound(msg).code === 'FileNotFound'
.
icons
For most VS Code icons, the codicon icon-font is used. Extensions can now reuse those icons in simple and declarative ways:
- The
vscode.ThemeIcon
type can now be instantiated with the name of a codicon. For example,new vscode.ThemeIcon("zap")
. - The
vscode.MarkdownString
type now supports the$(<name>)
inline syntax. For example,myMdString.appendMarkdown('Hello $(globe)');
. Note that to use codicons withinMarkdownString
, you must enable thesupportThemeIcons
constructor argument. commands
defined in an extension'spackage.json
file can now use a codicon for their icon. Use the inline syntax, for example"icon": "$(zap)"
.