Страница:
VS Code Extension API
Страницы
AB Experiments
Activate Environments in Terminal Using Environment Variables
Areas of Ownership for vscode‐python Team
Coding Guidelines
Coding
Commands
Components Test Management
Components
Dependency Injection with Inversify
Design Docs
Experiments
Extension Activation
Fixing "deactivate" command for virtual environments
Home
Interpreter and Environment Discovery
Issue Management
Limited support for Python 2.7
Migration to Python Tools Extensions
Mono Repo Set‐up Guide
New Method for Output Handling in Python Testing
Partial mode
Preview of the new Python bundle in Visual Studio Code
Product Package Management
Profiling
Python Environment APIs
Python Environment Search
Remove the need for reloading VS Code when changing language servers
Reporting a bug
Roadmap
SLAs
Setting descriptions
Sort environments by assumed usefulness
Stand Up
Submitting a pull request
Support poetry virtual environments
Testing Architecture Review
Testing
Troubleshoot ' 4058 ENOENT' error from NodeJS ‐ Python interpreter cannot be found
Troubleshooting TensorBoard integration in VS Code
Updating tooling versions
VS Code Extension API
1
VS Code Extension API
Brett Cannon редактировал(а) эту страницу 2021-01-14 14:33:36 -08:00
The VS Code extension API is divided into two distinct parts (conceptually):
- registration of handlers by which VS Code requests actions or data from an extension
- functions (and types, constants, etc.) by which an extension requests actions or data from VS Code
In addition to that concrete API, VS Code defines several other ways that extensions may interact with it or provide it resources:
- the
package.json
file (a superset of the npm package.json) defines static data about the extension. This includes commands, settings, language configuration, and debugger definitions. (Note that a number of items from that static data can be extended or overridden via the API.) - debug adapters (via "DAP") interact with VS Code (which acts as the debug client) to support debugging operations. They help make debuggers more independent from VS Code and its extensions.
- Language Servers (via "LSP") consolidate much of the language-specific functionality provided by registered handlers in the VS Code API, effectively replacing those handlers. As with debug adapters, this allows such language services to be more independent from VS Code and its extensions.
The Python extension for VS Code takes adavantage of all of the above.
Note: hypothetically, an extension could be written in Python, either directly or with a light typescript wrapper around the VS Code API. I'm just saying...
Analysis of Hooks Used by the Extension
Usage:
- `src/client/extension.ts'
- debug.registerDebugConfigurationProvider (+1)
- languages.registerCodeActionsProvider (+1)
- languages.registerDocumentFormattingEditProvider
- languages.registerDocumentRangeFormattingEditProvider
- languages.setLanguageConfiguration
src/client/activation/jedi.ts
- commands.registerCommand (+2)
- languages.registerCodeLensProvider (+2)
- languages.registerCompletionItemProvider (+1)
- languages.registerDefinitionProvider
- languages.registerDocumentSymbolProvider
- languages.registerHoverProvider
- languages.registerOnTypeFormattingEditProvider
- languages.registerReferenceProvider
- languages.registerRenameProvider
- languages.registerSignatureHelpProvider
src/client/common/application/debugService.ts
- debug.registerDebugAdapterDescriptorFactory
- debug.registerDebugAdapterTrackerFactory
- debug.registerDebugConfigurationProvider (+1)
- in other files:
- commands.registerCommand (3, incl. jedi)
- languages.registerCodeLensProvider (3, incl. jedi)
- languages.registerCompletionItemProvider (2, incl. jedi)
- languages.registerCodeActionsProvider (2, incl. extension.ts)
- commands.registerTextEditorCommand (1)
- languages.registerWorkspaceSymbolProvider (1)
- window.registerTreeDataProvider (1)
USED (by hook)
commands.registerCommand
------------------------------
src/client/activation/jedi.ts
src/client/common/application/commandManager.ts
src/client/providers/simpleRefactorProvider.ts
src/client/providers/simpleRefactorProvider.ts
commands.registerTextEditorCommand
------------------------------
src/client/common/application/commandManager.ts
debug.registerDebugAdapterDescriptorFactory
------------------------------
src/client/common/application/debugService.ts
debug.registerDebugAdapterTrackerFactory
------------------------------
src/client/common/application/debugService.ts
debug.registerDebugConfigurationProvider
------------------------------
src/client/common/application/debugService.ts
src/client/extension.ts
languages.registerCodeActionsProvider
------------------------------
src/client/extension.ts
src/client/providers/codeActionProvider/main.ts
languages.registerCodeLensProvider
------------------------------
src/client/activation/jedi.ts
src/client/datascience/datascience.ts
src/client/testing/codeLenses/main.ts
languages.registerCompletionItemProvider
------------------------------
src/client/activation/jedi.ts
src/client/common/application/languageService.ts
languages.registerDefinitionProvider
------------------------------
src/client/activation/jedi.ts
languages.registerDocumentFormattingEditProvider
------------------------------
src/client/extension.ts
languages.registerDocumentRangeFormattingEditProvider
------------------------------
src/client/extension.ts
languages.registerDocumentSymbolProvider
------------------------------
src/client/activation/jedi.ts
languages.registerHoverProvider
------------------------------
src/client/activation/jedi.ts
languages.registerOnTypeFormattingEditProvider
------------------------------
src/client/activation/jedi.ts
languages.registerReferenceProvider
------------------------------
src/client/activation/jedi.ts
languages.registerRenameProvider
------------------------------
src/client/activation/jedi.ts
languages.registerSignatureHelpProvider
------------------------------
src/client/activation/jedi.ts
languages.registerSignatureHelpProvider
------------------------------
src/client/activation/jedi.ts
languages.registerWorkspaceSymbolProvider
------------------------------
src/client/workspaceSymbols/main.ts
languages.setLanguageConfiguration
------------------------------
src/client/extension.ts
window.registerTreeDataProvider
------------------------------
src/client/datascience/liveshare/liveshareProxy.ts
total used: 21
NOT USED
languages.registerCallHierarchyProvider
languages.registerColorProvider
languages.registerDeclarationProvider
languages.registerDocumentHighlightProvider
languages.registerDocumentLinkProvider
languages.registerFoldingRangeProvider
languages.registerImplementationProvider
languages.registerSelectionRangeProvider
languages.registerTypeDefinitionProvider
tasks.registerTaskProvider
window.registerUriHandler
window.registerWebviewPanelSerializer
workspace.registerFileSystemProvider
workspace.registerTaskProvider
workspace.registerTextDocumentContentProvider
total not used: 15
USED (by file)
src/client/activation/jedi.ts
------------------------------
commands.registerCommand
languages.registerCodeLensProvider
languages.registerCompletionItemProvider
languages.registerDefinitionProvider
languages.registerDocumentSymbolProvider
languages.registerHoverProvider
languages.registerOnTypeFormattingEditProvider
languages.registerReferenceProvider
languages.registerRenameProvider
languages.registerSignatureHelpProvider
src/client/common/application/commandManager.ts
------------------------------
commands.registerCommand
commands.registerTextEditorCommand
src/client/common/application/debugService.ts
------------------------------
debug.registerDebugAdapterDescriptorFactory
debug.registerDebugAdapterTrackerFactory
debug.registerDebugConfigurationProvider
src/client/common/application/languageService.ts
------------------------------
languages.registerCompletionItemProvider
src/client/datascience/datascience.ts
------------------------------
languages.registerCodeLensProvider
src/client/datascience/liveshare/liveshareProxy.ts
------------------------------
window.registerTreeDataProvider
src/client/extension.ts
------------------------------
debug.registerDebugConfigurationProvider
languages.registerCodeActionsProvider
languages.registerDocumentFormattingEditProvider
languages.registerDocumentRangeFormattingEditProvider
languages.setLanguageConfiguration
src/client/providers/codeActionProvider/main.ts
------------------------------
languages.registerCodeActionsProvider
src/client/providers/simpleRefactorProvider.ts
------------------------------
commands.registerCommand
commands.registerCommand
src/client/testing/codeLenses/main.ts
------------------------------
languages.registerCodeLensProvider
src/client/workspaceSymbols/main.ts
------------------------------
languages.registerWorkspaceSymbolProvider
total files using hooks: 11
Extra Information
script to analyze our usage of the VS Code API
# XXX Find all "known" hooks (in node_modules/@types/vscode/index.d.ts).
# XXX Find all other uses of the VS Code API.
import re
import textwrap
def _regex_join_options(opts, indent=' '):
return f'\n{indent}|\n{indent}'.join(opts)
#######################################
# helpers for hooks
def find_known_hooks():
# For now we hard-code the list.
return [
'tasks.registerTaskProvider',
'commands.registerCommand',
'commands.registerTextEditorCommand',
'window.registerTreeDataProvider', # <T>
'window.registerUriHandler',
'window.registerWebviewPanelSerializer',
'workspace.registerFileSystemProvider',
'workspace.registerTaskProvider',
'workspace.registerTextDocumentContentProvider',
'languages.registerCallHierarchyProvider',
'languages.registerCodeActionsProvider',
'languages.registerCodeLensProvider',
'languages.registerColorProvider',
'languages.registerCompletionItemProvider',
'languages.registerDeclarationProvider',
'languages.registerDefinitionProvider',
'languages.registerDocumentFormattingEditProvider',
'languages.registerDocumentHighlightProvider',
'languages.registerDocumentLinkProvider',
'languages.registerDocumentRangeFormattingEditProvider',
'languages.registerDocumentSymbolProvider',
'languages.registerFoldingRangeProvider',
'languages.registerHoverProvider',
'languages.registerImplementationProvider',
'languages.registerOnTypeFormattingEditProvider',
'languages.registerReferenceProvider',
'languages.registerRenameProvider',
'languages.registerSelectionRangeProvider',
'languages.registerSignatureHelpProvider',
'languages.registerSignatureHelpProvider',
'languages.registerTypeDefinitionProvider',
'languages.registerWorkspaceSymbolProvider',
'languages.setLanguageConfiguration',
'debug.registerDebugAdapterDescriptorFactory',
'debug.registerDebugAdapterTrackerFactory',
'debug.registerDebugConfigurationProvider',
]
def iter_hooks(srclines, *, known=None, alts=None):
if not known:
known = find_known_hooks()
_hooks = (v.replace('.', '\.') for v in known + list(alts or ()))
regex = re.compile(
textwrap.dedent(rf'''
^
.*? \b
(
{_regex_join_options(_hooks, ' ')}
)
\s* (?: < [^>]+ > \s* )?
[(]
'''),
re.VERBOSE
)
for line in srclines:
m = regex.match(line)
if not m:
continue
hook, = m.groups()
yield alts.get(hook, hook) if alts else hook
def find_all_hooks(filenames, *, known=None, alts=None):
if not known:
known = find_known_hooks()
for filename in filenames or ():
with open(filename) as srcfile:
for hook in iter_hooks(srcfile, known=known, alts=alts):
yield filename, hook
def analyze_found_hooks(results):
hooks = {}
files = {}
for filename, hook in results:
try:
found = hooks[hook]
except KeyError:
found = hooks[hook] = []
if filename not in found:
found.append(filename)
try:
found = files[filename]
except KeyError:
found = files[filename] = []
found.append(hook)
return hooks, files
#######################################
# commands
# hooks
HOOKS_ALTS = {
'.registerTreeDataProvider': 'window.registerTreeDataProvider',
}
def cmd_hooks(filenames, show=None):
try:
run_cmd = CMD_HOOKS_SHOW[show or 'summary']
except KeyError:
raise ValueError(f'unsupported --show {show!r}')
if run_cmd is None:
raise NotImplementedError(show)
known = find_known_hooks()
run_cmd(
find_all_hooks(filenames, known=known, alts=HOOKS_ALTS),
filenames=filenames,
known=known,
)
def cmd_hooks_raw(results, **ignored):
total = 0
for filename, hook in results: # We do not sort.
print(f'{filename:50} {hook}')
total += 1
print('----')
print(f'total: {total}')
print()
def cmd_hooks_by_hook(results, known, **ignored):
hooks, _= analyze_found_hooks(results)
for hook in sorted(hooks, key=lambda h: (-len(hooks[h]), h)):
found = hooks.get(hook, ())
if not found:
continue
print()
print(f'{hook} ({len(hooks[hook])})')
print('------------------------------')
for filename in sorted(found):
print(' ', filename)
print()
def cmd_hooks_by_file(results, **ignored):
_, files = analyze_found_hooks(results)
for filename in sorted(files, key=lambda f: (-len(files[f]), f)):
print()
print(f'{filename} ({len(files[filename])})')
print('------------------------------')
for hook in sorted(files[filename]):
print(' ', hook)
print()
HOOKS_EXPECTED = [
'commands.registerCommand',
'commands.registerTextEditorCommand',
'window.registerTreeDataProvider',
'languages.registerCodeActionsProvider',
'languages.registerCodeLensProvider',
'languages.registerCompletionItemProvider',
'languages.registerDefinitionProvider',
'languages.registerDocumentFormattingEditProvider',
'languages.registerDocumentRangeFormattingEditProvider',
'languages.registerDocumentSymbolProvider',
'languages.registerHoverProvider',
'languages.registerOnTypeFormattingEditProvider',
'languages.registerReferenceProvider',
'languages.registerRenameProvider',
'languages.registerSignatureHelpProvider',
'languages.registerSignatureHelpProvider',
'languages.registerWorkspaceSymbolProvider',
'languages.setLanguageConfiguration',
'debug.registerDebugAdapterDescriptorFactory',
'debug.registerDebugAdapterTrackerFactory',
'debug.registerDebugConfigurationProvider',
]
def cmd_hooks_summary(results, known, filenames, **ignored):
single = len(filenames) == 1
hooks, files = analyze_found_hooks(results)
print()
print(f'using {len(hooks)} hooks:')
for hook in sorted(hooks, key=lambda h: (-len(hooks[h]), h)):
if single:
print(f' ', hook)
else:
print(f' {len(hooks[hook]):>2} {hook}')
if len(filenames) > 100: # an approximation of "all"
missing = set(HOOKS_EXPECTED) - set(hooks)
if missing:
print()
print(f'expected but not found ({len(missing)}):')
for hook in sorted(missing):
print(' ', hook)
notused = set(known) - set(hooks)
if notused:
print()
print(f'not used ({len(notused)}):')
for hook in sorted(notused):
print(' ', hook)
if not single:
print()
print(f'found {len(files)} files using hooks:')
for filename in sorted(files, key=lambda f: (-len(files[f]), f)):
print(f' {len(files[filename]):>2} {filename}')
CMD_HOOKS_SHOW = {
'raw': cmd_hooks_raw,
'hooks': cmd_hooks_by_hook,
'files': cmd_hooks_by_file,
'summary': cmd_hooks_summary,
}
# api
def cmd_api(filenames, show=None):
try:
run_cmd = CMD_API_SHOW[show or 'summary']
except KeyError:
raise ValueError(f'unsupported --show {show!r}')
if run_cmd is None:
raise NotImplementedError(show)
run_cmd(filenames)
CMD_API_SHOW = {
'raw': None,
'hooks': None,
'files': None,
'summary': None,
}
# the registry
COMMANDS = {
'hooks': cmd_hooks,
'api': cmd_api,
}
COMMANDS_DEFAULT = 'hooks'
SHOW = {
'hooks': CMD_HOOKS_SHOW,
'api': CMD_API_SHOW,
}
#######################################
# the script
import sys
def parse_args(argv=sys.argv[1:], prog=sys.argv[0]):
import argparse
# Set up the "default" command.
if argv and argv[0] not in COMMANDS:
if '.' in argv[0] or argv[0].startswith('-'):
# This doesn't guard against "--".
if '-h' in argv or '--help' in argv:
argv = ['--help']
else:
# Use a sensible default for now.
argv.insert(0, COMMANDS_DEFAULT)
parser = argparse.ArgumentParser(
prog=prog,
)
subs = parser.add_subparsers(dest='cmd')
for cmd in sorted(COMMANDS):
sub = subs.add_parser(cmd)
if cmd in SHOW:
sub.add_argument(
'--show', choices=sorted(SHOW[cmd]), default='summary',
)
sub.add_argument('filenames', nargs='+')
args = parser.parse_args(argv)
ns = vars(args)
cmd = ns.pop('cmd')
return cmd, ns
def main(cmd, **cmd_kwargs):
try:
run_cmd = COMMANDS[cmd]
except KeyError:
raise ValueError(f'unsupported --cmd {cmd!r}')
run_cmd(**cmd_kwargs)
if __name__ == '__main__':
cmd, kwargs = parse_args()
main(cmd, **kwargs)