This package provides:
- hover@0.1.0
- outline-view@0.1.0
- find-references@0.1.0
- symbol.provider@1.0.0
- autocomplete.provider@5.1.0
This package consumes:
Made for Pulsar!
This package was written specifically for Pulsar and did not exist in the Atom package repository.
The intention of this plug-in is to allow VSCode extensions to be installed in
Pulsar, and behave like they were Pulsar native. It does that by mapping
VSCode's APIs to Pulsar's ones (not Atom - this plug-in uses some specific
APIs that were added in Pulsar) and then adapting activation code so that such
extensions can work. Each extension will be installed in the same directory as
Pulsar's packages, so they are essentially indistinguishable from Pulsar's
"normal" packages - but they still need to vscode-compat extension to be
installed and active otherwise they won't work.
There are a couple changes that one needs to be aware: VSCode extensions run in a webworker, so they don't block the main thread. That means, if an extension is misbehaving, you will get a spike in your CPU or your editor consuming a lot of memory, but the editor itself might not block, freeze, or appear to be slowing down. In Pulsar, packages run in the main thread - the same as the UI, autocomplete, and everything else. This means that the editor will freeze if something goes wrong - but it also means we can open up the door for some very cool experiments in the future.
This project is written with a lot of AI tools. Multiple tools are being used in this translation layer - Claude and Codex are the main ones, but also some local models and other approaches. I tried, and failed, multiple times to write this translation layer manuall - the VSCode API is extensive and there are a lot of undocumented behaviors, internal structure, and other unreliable information that some extensions use. The worst part is that some of these extensions are not open-source, which translated to me trying to read minified extension code, trying to understand what mapped to what, and having to implement all this behavior by hand, just to reload the extension and see it fail in different places.
If you are uncomfortable with AI code, be warned. While I don't consider this project fully "vibe-coded", more than 90% of this code is AI generated. I wish that it didn't - I really do. But it is what it is.
Use the built-in extension browser command:
pulsar-vscode-compat:browse-extensions

The browser installs from Open VSX. After installation it tries to load and activate the generated Pulsar package immediately with Pulsar's package manager. A reload prompt is only shown if immediate activation fails. Platform-specific Open VSX artifacts are selected when available.
The compatibility layer tries really hard to map the extension activation hooks
into Pulsar ones - for example, opening up a Python source code should trigger
the activation if that's what the extension defined; triggering up a command
also works (but the command's name might be different from VSCode, for now at
least). For all purposes, the VSCode extension is installed as if it's a
Pulsar package - so you can uninstall it from the Pulsar's package manager,
you will see the extension code under the same directory as Pulsar's ones
(usually ~/.pulsar/packages), and you can see the README, and the configs
available, under Pulsar's settings panel - for all effects and purposes, as soon
as it is installed, a VSCode extension is a Pulsar package.
Deactivating (and reloading) the VSCode Compat, while you have VSCode extensions installed, will probably crash them. We might, in the future, offer a warning that the compatibility layer is not present, but installing a VSCode extension under Pulsar, then disabling/uninstalling the compat layer and making the VSCode extension still works won't ever be supported.
This package provides two pieces:
vscode API implementation under lib/vscode.js.Wrapped VSCode extensions are installed as normal Pulsar packages named like:
vscode-<publisher>-<name>
Each generated wrapper contains the original VSCode extension under:
extension/
and a generated Pulsar entry point under:
lib/main.js
The generated wrapper also creates a local package shim:
node_modules/vscode/index.js
That shim is intentionally local to the generated wrapper package. There is no global require('vscode') hook in Pulsar core. The generated wrapper first activates pulsar-vscode-compat, then loads the original VSCode extension. If pulsar-vscode-compat is missing, disabled, or fails to activate, the generated wrapper logs a warning and does not load the VSCode extension.
VSCode extension activation maps to Pulsar package activation.
The generated wrapper translates common VSCode activationEvents into native Pulsar lazy activation metadata:
onCommand:<id> becomes activationCommands on atom-workspace.onLanguage:<id> becomes Pulsar grammar activation hooks such as source.ts:root-scope-used.contributes.commands and contributes.languages when activationEvents is omitted.*, onStartupFinished, and unsupported events such as workspaceContains, onView, onUri, onDebug, and onTaskType fall back to normal startup activation rather than being silently missed.Once Pulsar activates the wrapper package, its activate(state) does this:
atom.packages.activatePackage('pulsar-vscode-compat').pulsar-vscode-compat/lib/vscode.js.extension/.ExtensionContext.activate(context).deactivate() calls the original extension's deactivate() when present, then disposes the compatibility ExtensionContext.
registerCommand maps to atom.commands.add('atom-workspace', ...).registerTextEditorCommand maps to atom.commands.add('atom-text-editor', ...).executeCommand first calls a registered VSCode command callback directly when one exists.atom.commands.dispatch(...).vscode.executeCompletionItemProvider is specially routed to the internal completion provider registry.The wrapper reads contributes.commands from the original VSCode package.json and uses the VSCode category, title, and description as Pulsar command metadata. This gives the command palette human-readable labels like Calva: Connect to a Running REPL Server while preserving the raw command id, such as calva.connect, for command execution.
TextEditor/buffer objects via TextDocument.openTextDocument maps file URIs and paths to atom.workspace.createItemForURI(...) so documents can be opened without necessarily creating a visible pane.showTextDocument maps to opening/revealing a Pulsar editor pane through atom.workspace.open(...).textDocuments maps to atom.workspace.getTextEditors().workspaceFolders maps to atom.project.getPaths().getWorkspaceFolder(uri) finds the owning Pulsar project path.applyEdit applies VSCode WorkspaceEdit text edits to Pulsar buffers and handles simple create/delete/rename file operations.getConfiguration(section) maps VSCode configuration keys onto Pulsar config keys. For wrapped extensions, contributed configuration from a single VSCode section is shown as package-level settings in Pulsar's package UI, while workspace.getConfiguration(section) still reads/writes the corresponding wrapper setting. Older nested wrapperPackage.section.key values are still read as a fallback.workspace.fs maps to Node fs.promises for the file: scheme: stat, readDirectory, createDirectory, readFile, writeFile, delete, rename, and copy.FileSystemError factories are available.registerFileSystemProvider registers custom URI schemes for workspace.fs operations.registerTextDocumentContentProvider supports virtual/read-only documents for custom schemes.createFileSystemWatcher uses Pulsar's global atom.watchPath when available and matches common VSCode glob patterns without an undeclared minimatch dependency.findFiles handles VSCode RelativePattern objects, exact relative paths, common glob patterns, exclusions, and maxResults without an undeclared glob dependency.Document lifecycle events are best-effort translations from Pulsar editor/buffer events:
onDidOpenTextDocumentonDidCloseTextDocumentonDidChangeTextDocumentonDidSaveTextDocumentonWillSaveTextDocumentWorkspace folder and file operation events are present, but mostly placeholders unless explicitly fired by implemented operations.
VSCode:
vscode.languages.registerCompletionItemProvider(selector, provider, ...triggerCharacters)
Pulsar mapping:
autocomplete-plus providers.pulsar-vscode-compat provides an autocomplete.provider service from main.js.lib/adapters/completion-adapter.js.CompletionItem objects are converted to autocomplete-plus suggestions.resolveCompletionItem maps to autocomplete-plus detail resolution.Limitations:
VSCode:
vscode.languages.registerHoverProvider(selector, provider)
Pulsar mapping:
hover service.This is implemented in:
lib/adapters/hover-adapter.js
lib/service/hover.js
VSCode:
vscode.languages.createDiagnosticCollection(name)
vscode.languages.getDiagnostics(uri?)
Pulsar mapping:
DiagnosticCollection stores diagnostics internally.linter-indie service is available, diagnostics are published through a Linter indie provider named VSCode Compatibility Layer.linter-indie, diagnostics remain available through the compatibility API but are not shown as native lint messages.VSCode:
registerDefinitionProvider
registerDeclarationProvider
registerImplementationProvider
registerTypeDefinitionProvider
registerReferenceProvider / registerReferencesProvider
registerDocumentSymbolProvider
registerWorkspaceSymbolProvider
Pulsar mapping:
symbol.provider service.main.js provides symbol.provider from languages._symbolProviders.Location/LocationLink objects into symbols that Pulsar's symbols UI can open.Implemented in:
lib/adapters/definition-adapter.js
lib/namespaces/languages.js
Limitations:
VSCode:
vscode.languages.registerCodeActionsProvider(selector, provider, metadata)
Pulsar mapping:
vscode-compat:code-action
Code Actions, is added to text editors.showQuickPick.workspace.applyEdit.commands.executeCommand.Limitations:
VSCode:
vscode.languages.registerRenameProvider(selector, provider)
Pulsar mapping:
vscode-compat:rename-symbol
Rename Symbol, is added to text editors.showInputBox, calls provideRenameEdits, and applies the returned workspace edit.Limitations:
prepareRename support is not currently implemented.VSCode:
registerDocumentFormattingEditProvider
registerDocumentRangeFormattingEditProvider
registerOnTypeFormattingEditProvider
Pulsar mapping:
vscode-compat:format-selection
Implemented in:
lib/adapters/formatting-adapter.js
VSCode:
vscode.languages.registerSignatureHelpProvider(selector, provider, metadata)
Pulsar mapping:
SignatureHelpContext.Limitations:
VSCode:
vscode.languages.registerDocumentHighlightProvider(selector, provider)
Pulsar mapping:
type: 'highlight' and class vscode-document-highlight.Implemented in:
lib/adapters/highlight-adapter.js
VSCode:
vscode.languages.registerCodeLensProvider(selector, provider)
Pulsar mapping:
Implemented in:
lib/adapters/codelens-adapter.js
VSCode:
vscode.languages.registerInlayHintsProvider(selector, provider)
Pulsar mapping:
Implemented in:
lib/adapters/inlay-hint-adapter.js
VSCode:
vscode.languages.registerFoldingRangeProvider(selector, provider)
Pulsar mapping:
VSCode:
vscode.window.createOutputChannel(name)
Pulsar mapping:
Implemented in:
lib/types/output-channel.js
lib/namespaces/window.js
VSCode:
vscode.window.createStatusBarItem(...)
vscode.window.setStatusBarMessage(...)
Pulsar mapping:
createStatusBarItem maps to Pulsar's status-bar service when available.setStatusBarMessage creates a temporary left status bar tile.VSCode:
vscode.window.showQuickPick(...)
vscode.window.createQuickPick()
vscode.window.showInputBox(...)
Pulsar mapping:
showQuickPick maps to atom-select-list inside a modal panel.createQuickPick implements a VSCode-like QuickPick object with events such as onDidChangeActive, onDidChangeSelection, onDidAccept, and onDidHide.showInputBox maps to a mini atom-text-editor inside a modal panel.Limitations:
VSCode:
showInformationMessage
showWarningMessage
showErrorMessage
Pulsar mapping:
atom.notifications.addInfo, addWarning, and addError.VSCode:
vscode.window.createTerminal(...)
Pulsar mapping:
pty.open, pty.handleInput, pty.close, onDidWrite, onDidClose, and onDidExit patterns.hideFromUser is requested.This is intended to support extensions such as Calva that use pseudoterminals for REPL interaction/status output.
Limitations:
VSCode:
vscode.window.activeTextEditor
vscode.window.visibleTextEditors
vscode.window.onDidChangeTextEditorSelection
vscode.window.tabGroups
vscode.window.createTextEditorDecorationType(...)
editor.setDecorations(...)
Pulsar mapping:
TextEditor wraps Pulsar TextEditor instances, with stable wrapper identity per underlying editor so extensions can compare event.textEditor === vscode.window.activeTextEditor.atom.workspace, with fallbacks that remember the last active editor after focus moves into a webview.onDidChangeTextEditorSelection events.tabGroups.all and activeTabGroup are synthesized from Pulsar center panes.Limitations:
VSCode:
vscode.window.registerTreeDataProvider(...)
vscode.window.createTreeView(...)
Pulsar mapping:
outline-view service.Limitations:
VSCode:
vscode.window.createWebviewPanel(...)
Pulsar mapping:
file: document instead of srcdoc, which avoids inherited Pulsar/Electron CSP blocking the extension's own nonce scripts.acquireVsCodeApi(), postMessage, setState, and getState before extension webview scripts run.webview.onDidReceiveMessage and webview.postMessage bridge messages between the extension and iframe.asWebviewUri currently returns the input URI, while local-resource loading relies on the temporary file: document's same-origin access.vscode-dark; active theme changes post live updates into existing webviews.createWebviewPanel honors ViewColumn.Active, One, Beside, and numeric columns by mapping them to center pane opens/splits.panel.viewColumn and panel.reveal(...) are implemented enough for extensions that manage editor columns.Still no-op/stubbed webview APIs:
registerWebviewPanelSerializerregisterWebviewViewProviderVSCode:
vscode.extensions.getExtension(id)
vscode.extensions.all
Pulsar mapping:
extension/package.json and wrapper package.json.activate() waits for activation and resolves to the original extension's exports.vscode.git compatibility API is available.VSCode:
vscode.env
Pulsar mapping:
atom.clipboard.openExternal maps to Electron shell opening.appName, appRoot, session id, language, shell, URI scheme, and theme-ish values are synthesized from Pulsar/Electron where possible.These APIs have real behavior and are expected to be useful for compatibility work:
commands.registerCommand, registerTextEditorCommand, executeCommand, getCommands.contributes.commands.workspace.openTextDocument, showTextDocument, textDocuments, workspaceFolders, getWorkspaceFolder, and asRelativePath.workspace.findFiles supports strings and RelativePattern with dependency-free glob matching for common *, **, ?, and {a,b} patterns.workspace.findTextInFiles is implemented as a best-effort search using Pulsar project scan when available, with a filesystem fallback.workspace.getConfiguration for wrapper-owned extension configuration.workspace.applyEdit for text edits and simple file operations.workspace.fs maps to Node fs.promises for local file: operations and dispatches to registered FileSystemProviders for custom schemes.vscode-compat:code-action command.vscode-compat:rename-symbol command.acquireVsCodeApi, message passing, CSP/resource handling, theme variable injection, live theme updates, and ViewColumn/reveal handling.window.tabGroups / TabInputText / TabInputWebview for open Pulsar panes and compat webviews.atom.watchPath integration.NotebookCellOutput and NotebookCellOutputItem.AbortSignal with Node events.setMaxListeners, needed by some bundled browser/agent SDK code.These APIs exist to prevent extensions from failing during activation, but do little or nothing:
languages.setLanguageConfiguration is best-effort and currently does not alter grammar behavior.languages.registerDocumentLinkProvider returns a disposable but does not wire links into the editor.languages.registerColorProvider is stubbed.languages.registerSelectionRangeProvider is stubbed.languages.registerLinkedEditingRangeProvider is stubbed.languages.registerDocumentDropEditProvider / registerDocumentOnDropEditProvider are stubbed.languages.registerEvaluatableExpressionProvider is stubbed.languages.registerInlineCompletionItemProvider is stubbed.languages.registerInlineValuesProvider is stubbed.languages.registerCallHierarchyProvider is stubbed.languages.registerTypeHierarchyProvider is stubbed.executeTask rejects because tasks are not supported.reveal, selection, checkbox, visibility, and badge behavior are incomplete.Important compatibility gaps remain:
In the past, I had an interesting idea that I never really was able to implement
Now, what if Pulsar could offer a VSCode API that does this? For example,
VSCode's Hover
API
allows one to decide if they want to show plain text or markdown - but inside
Pulsar, we could allow the user to provide another element - something like
htmlHoverMessage - so that an user could offer both hoverMessage and this
new parameter, and Pulsar would prefer the former, rendering a "richer version"
of such decoration.
For a plug-in author, this seems huge - one could implement only a single version of their extension, written in the VSCOde API, and then get a "better version" of it, for free, just by adding some small parameters on editors that support that.
None of this is implemented right now - but it's a good idea for the future.
autocomplete-plus, symbols-view, linter-indie, status-bar, atom-select-list, atom.notifications, atom.commands, and atom.workspace.The current practical targets are real extensions and workflows rather than abstract API completeness.
Calva should be usable enough to:
calva.connect through the quick-pick/input flow.Claude Code should be usable enough to:
acquireVsCodeApi messaging.ViewColumn, window.tabGroups, and TabInputWebview.workspace.findFiles(RelativePattern) support.This README describes the current state of the compatibility layer, not a guarantee of full VSCode API compatibility.