├── .gitignore ├── images ├── logo.png └── completion.gif ├── publish.bat ├── .vscode-test.mjs ├── .vscodeignore ├── .vscode ├── extensions.json └── launch.json ├── jsconfig.json ├── CHANGELOG.md ├── test └── extension.test.js ├── .github └── workflows │ └── publish.yml ├── package.py ├── eslint.config.mjs ├── LICENSE ├── package.json ├── vsc-extension-quickstart.md ├── README.md └── extension.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode-test/ 3 | *.vsix 4 | -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHUTB/vsc/HEAD/images/logo.png -------------------------------------------------------------------------------- /images/completion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHUTB/vsc/HEAD/images/completion.gif -------------------------------------------------------------------------------- /publish.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal enabledelayedexpansion 3 | chcp 65001 4 | 5 | call vsce package 6 | 7 | call vsce publish -------------------------------------------------------------------------------- /.vscode-test.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from '@vscode/test-cli'; 2 | 3 | export default defineConfig({ 4 | files: 'test/**/*.test.js', 5 | }); 6 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | test/** 4 | .gitignore 5 | .yarnrc 6 | vsc-extension-quickstart.md 7 | **/jsconfig.json 8 | **/*.map 9 | **/eslint.config.mjs 10 | **/.vscode-test.* 11 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint", 6 | "ms-vscode.extension-test-runner" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2022", 5 | "checkJs": false, /* Typecheck .js files. */ 6 | "lib": [ 7 | "ES2022" 8 | ] 9 | }, 10 | "exclude": [ 11 | "node_modules" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "carlaapi" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release -------------------------------------------------------------------------------- /test/extension.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | const vscode = require('vscode'); 6 | // const myExtension = require('../extension'); 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.strictEqual(-1, [1, 2, 3].indexOf(5)); 13 | assert.strictEqual(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ] 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - "*" 5 | 6 | name: Deploy Extension 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v4 13 | with: 14 | node-version: 20 15 | - run: npm ci 16 | - name: Publish to Visual Studio Marketplace 17 | uses: HaaLeo/publish-vscode-extension@v2 18 | with: 19 | pat: ${{ secrets.VS_MARKETPLACE_TOKEN }} 20 | registryUrl: https://marketplace.visualstudio.com -------------------------------------------------------------------------------- /package.py: -------------------------------------------------------------------------------- 1 | # 将 vscode 及其依赖项打包为一个独立的可执行文件 2 | # 所有下载的文件均放到 build 目录中 3 | 4 | import requests 5 | 6 | 7 | # 参考:https://code.visualstudio.com/docs/supporting/faq#_previous-release-versions 8 | # 注意区分可执行文件和zip包 9 | url = 'https://update.code.visualstudio.com/1.76.2/win32-x64-archive/stable' 10 | 11 | # 清除代理,否则会出错:Unable to connect to proxy 12 | session = requests.Session() 13 | session.trust_env = False 14 | 15 | vsc_file = session.get(url) 16 | 17 | # 如果不存在 build 目录,则创建它 18 | import os 19 | 20 | if not os.path.exists('build'): 21 | os.makedirs('build') 22 | 23 | open('build/vsc.zip', 'wb').write(vsc_file.content) -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import globals from "globals"; 2 | 3 | export default [{ 4 | files: ["**/*.js"], 5 | languageOptions: { 6 | globals: { 7 | ...globals.commonjs, 8 | ...globals.node, 9 | ...globals.mocha, 10 | }, 11 | 12 | ecmaVersion: 2022, 13 | sourceType: "module", 14 | }, 15 | 16 | rules: { 17 | "no-const-assign": "warn", 18 | "no-this-before-super": "warn", 19 | "no-undef": "warn", 20 | "no-unreachable": "warn", 21 | "no-unused-vars": "warn", 22 | "constructor-super": "warn", 23 | "valid-typeof": "warn", 24 | }, 25 | }]; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de 4 | Barcelona (UAB). 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hutb", 3 | "displayName": "hutb", 4 | "publisher": "OpenHUTB", 5 | "description": "为 Carla 自动驾驶模拟器 API、AirSim 无人机模拟器 API、Mujoco 模拟器 API 提供智能代码补全、文档和 IntelliSense 支持。", 6 | "icon": "images/logo.png", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/OpenHUTB/vscode_ext" 10 | }, 11 | "version": "0.1.3", 12 | "engines": { 13 | "vscode": "^1.94.0" 14 | }, 15 | "categories": [ 16 | "Programming Languages" 17 | ], 18 | "activationEvents": [ 19 | "onLanguage:python" 20 | ], 21 | "main": "./extension.js", 22 | "contributes": { 23 | "languages": [{ 24 | "id": "python", 25 | "extensions": [".py"] 26 | }], 27 | "configuration": { 28 | "title": "CARLA API", 29 | "properties": { 30 | "carlaapi.showClasses": { 31 | "type": "boolean", 32 | "default": true, 33 | "description": "Show class completions" 34 | }, 35 | "carlaapi.showMethods": { 36 | "type": "boolean", 37 | "default": true, 38 | "description": "Show method completions" 39 | }, 40 | "carlaapi.showProperties": { 41 | "type": "boolean", 42 | "default": true, 43 | "description": "Show property completions" 44 | } 45 | } 46 | } 47 | }, 48 | "scripts": { 49 | "lint": "eslint .", 50 | "pretest": "npm run lint", 51 | "test": "vscode-test" 52 | }, 53 | "devDependencies": { 54 | "@types/vscode": "^1.94.0", 55 | "@types/mocha": "^10.0.9", 56 | "@types/node": "20.x", 57 | "eslint": "^9.13.0", 58 | "@vscode/test-cli": "^0.0.10", 59 | "@vscode/test-electron": "^2.4.1" 60 | } 61 | } -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your extension and command. 7 | * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `extension.js` - this is the main file where you will provide the implementation of your command. 9 | * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 10 | * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. 11 | 12 | ## Get up and running straight away 13 | 14 | * Press `F5` to open a new window with your extension loaded. 15 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 16 | * Set breakpoints in your code inside `extension.js` to debug your extension. 17 | * Find output from your extension in the debug console. 18 | 19 | ## Make changes 20 | 21 | * You can relaunch the extension from the debug toolbar after changing code in `extension.js`. 22 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | ## Explore the API 25 | 26 | * You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 27 | 28 | ## Run tests 29 | 30 | * Install the [Extension Test Runner](https://marketplace.visualstudio.com/items?itemName=ms-vscode.extension-test-runner) 31 | * Open the Testing view from the activity bar and click the Run Test" button, or use the hotkey `Ctrl/Cmd + ; A` 32 | * See the output of the test result in the Test Results view. 33 | * Make changes to `test/extension.test.js` or create new test files inside the `test` folder. 34 | * The provided test runner will only consider files matching the name pattern `**.test.js`. 35 | * You can create folders inside the `test` folder to structure your tests any way you want. 36 | 37 | ## Go further 38 | 39 | * [Follow UX guidelines](https://code.visualstudio.com/api/ux-guidelines/overview) to create extensions that seamlessly integrate with VS Code's native interface and patterns. 40 | * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code extension marketplace. 41 | * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 42 | * Integrate to the [report issue](https://code.visualstudio.com/api/get-started/wrapping-up#issue-reporting) flow to get issue and feature requests reported by users. 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Visual Studio Code 的 HUTB 模拟器 API 扩展 2 | 3 | 为 Carla 自动驾驶模拟器 API、AirSim 无人机模拟器 API、Mujoco 模拟器 API 提供智能代码补全、文档和 IntelliSense 支持。 4 | 5 | ## 特性 6 | 7 | ### 智能代码补全 8 | 9 | - Carla 类、方法和属性的上下文感知补全 10 | - 输入类名时自动显示相关方法和属性 11 | - 完成项目中的富文本的预览 12 | 13 | ![Code Completion](images/completion.gif) 14 | 15 | 16 | ### 方法签名帮助 17 | 18 | - 键入方法调用时的实时参数信息 19 | - 参数类型和默认值 20 | - 每个参数的文档 21 | 22 | 23 | ### 悬停文档 24 | - 有关类、方法和属性的悬停的详细文档 25 | - 显示方法签名和返回类型 26 | - 显示属性的访问信息(读/写) 27 | 28 | ### 智能上下文检测 29 | - 仅显示基于上下文的相关完成内容 30 | - 开始新语句时的类建议 31 | - 仅针对当前正在输入的类提供方法和属性建议 32 | 33 | ## 要求 34 | 35 | - Visual Studio Code version 1.94.0 或更高版本 36 | - VS Code 的 Python 扩展 37 | - 在您的环境中安装 Carla Python API(可选) 38 | 39 | ## 安装 40 | 41 | 1. 通过 VS Code 安装扩展: 42 | - 打开 VS Code 43 | - 前往左侧工具栏中的扩展 (Ctrl+Shift+X) 44 | - 搜索 "hutb" 45 | - 点击安装(Install) 46 | 47 | 2. 或者,下载 VSIX 文件并手动安装: 48 | ```bash 49 | code --install-extension hutb-0.0.4.vsix 50 | ``` 51 | 52 | ## 使用 53 | 54 | 编辑 Python 文件时,该扩展程序会自动激活。以下是主要功能的使用方法: 55 | 56 | 1. **类名补全** 57 | - 开始输入 Carla 类名 58 | - 按 Ctrl+Space 查看可用的类 59 | 60 | 2. **方法和属性补全** 61 | - 输入一个类名,后跟一个点(例如, `Actor.`) 62 | - 完成将自动显示可用的方法和属性 63 | 64 | 3. **签名帮助** 65 | - 在方法名称后输入一个左括号 66 | - 签名帮助将显示参数信息 67 | - 使用逗号浏览参数 68 | 69 | ## 示例 70 | 71 | ```python 72 | # 该扩展将提供补全和文档 73 | world = client.get_world() # 显示 World 类的方法 74 | actor = world.spawn_actor() # 显示 spawn_actor 参数 75 | ``` 76 | 77 | ## 已知的问题 78 | 79 | - 目前不支持方法重载 80 | - 某些复杂类型提示可能无法正确解析 81 | - 某些 Carla API 方法的文档可能不完整 82 | 83 | ## 故障排除 84 | 85 | 如果您遇到任何问题: 86 | 87 | 1. 确保安装了最新版本的 VS Code 88 | 2. 检查 Python 扩展是否已安装并配置 89 | 3. 验证您的 hutb Python API 是否已正确安装 90 | 4. 如果没有出现补全,请尝试重新加载 VS Code 91 | 92 | ## 贡献 93 | 94 | 1. Fork 该仓库 95 | 96 | ``` bash 97 | git clone https://github.com/OpenHUTB/vscode_ext 98 | ``` 99 | 100 | 2. 创建一个特性分支 101 | 3. 提交(commit)你的修改 102 | 4. 推送(push) 到特性分支 103 | 5. 创建拉取请求(Pull Request) 104 | 105 | ## 发布到市场 106 | 107 | 1.下载并安装 [node 20](https://nodejs.org/en/download) ;并安装`vsce` 108 | ```shell 109 | npm i -g vsce 110 | ``` 111 | 112 | 2.打包成`vsix`: 113 | ```shell 114 | vsce package 115 | ``` 116 | 117 | 3.打开`extension.js`,然后按 F5(Run->Start Debugging),会打开一个新的VScode,新建python脚本,以测试效果。 118 | 119 | 4.登录: 120 | ```shell 121 | vsce login OpenHUTB 122 | ``` 123 | 输入 Token 。 124 | 125 | 5.发布 126 | ```shell 127 | vsce publish 128 | ``` 129 | 130 | 等待几分钟就可以在 [扩展的链接](https://marketplace.visualstudio.com/items?itemName=OpenHUTB.hutbapi) 、[Hub的链接](https://marketplace.visualstudio.com/manage/publishers/OpenHUTB/extensions/hutbapi/hub) 中看到插件 131 | 132 | 133 | 6.(其他)取消发布 134 | 135 | 访问 [管理页面](https://marketplace.visualstudio.com/manage/) ,右键所需要删除的扩展进行删除。 136 | 137 | ## 发行说明 138 | 139 | ### 0.0.1 - 初始版本 140 | - Carla API 类的补全完成 141 | - 方法和属性建议 142 | - 签名帮助 143 | - 悬停文档 144 | - 上下文感知补全 145 | 146 | ## 计划的功能 147 | 148 | - 支持方法重载 149 | - 改进的类型提示解析 150 | - 与 hutb 文档集成 151 | - 常见 Carla 操作的快速操作 152 | - Code snippets for common patterns 153 | 154 | ## 许可证 155 | 156 | 此扩展遵循 MIT 许可证。详情请参阅 [LICENSE 文件](./LICENSE) 。 157 | 158 | ## 致谢 159 | 160 | - Carla 仿真器团队提供的出色文档 161 | - VS Code 扩展开发社区 162 | - [Publish VS Code Extension — GitHub Action](https://github.com/marketplace/actions/publish-vs-code-extension) 163 | - [carlaApiExtension](https://github.com/OpenHUTB/vscode_ext) 164 | - [发布方法](https://juejin.cn/post/7402800227810852900) 。 165 | 166 | ## 支持 167 | 168 | 对于错误报告和功能请求,请使用 GitHub 问题跟踪器: 169 | 170 | [https://github.com/OpenHUTB/vscode_ext/issues](https://github.com/OpenHUTB/vscode_ext/issues) 171 | 172 | --- 173 | 174 | **开始享受使用 hutb API 扩展吧!** 175 | -------------------------------------------------------------------------------- /extension.js: -------------------------------------------------------------------------------- 1 | const vscode = require('vscode'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | 5 | let apiDefinition = null; 6 | 7 | /** 8 | * Load the CARLA API definition from the utils folder 9 | * @param {string} extensionPath 10 | * @returns {Object|null} 11 | */ 12 | function loadApiDefinition(extensionPath) { 13 | try { 14 | const jsonPath = path.join(extensionPath, 'utils', 'carla_api.json'); 15 | const jsonContent = fs.readFileSync(jsonPath, 'utf8'); 16 | return JSON.parse(jsonContent); 17 | } catch (error) { 18 | console.error('Failed to load CARLA API definition:', error); 19 | vscode.window.showErrorMessage('Failed to load CARLA API definition file'); 20 | return null; 21 | } 22 | } 23 | 24 | /** 25 | * Parse method signature to extract parameter details 26 | * @param {string} signature 27 | * @returns {Array<{name: string, type?: string, default?: string}>} 28 | */ 29 | function parseMethodSignature(signature) { 30 | const match = signature.match(/\((.*?)\)/); 31 | if (match && match[1]) { 32 | return match[1].split(',') 33 | .map(param => param.trim()) 34 | .filter(param => param && !param.includes('self')) 35 | .map(param => { 36 | const result = { name: '', type: undefined, default: undefined }; 37 | 38 | // Handle type hints 39 | const typeMatch = param.match(/(\w+)\s*:\s*([^=]+?)(?:\s*=\s*(.+))?$/); 40 | if (typeMatch) { 41 | result.name = typeMatch[1]; 42 | result.type = typeMatch[2].trim(); 43 | if (typeMatch[3]) { 44 | result.default = typeMatch[3].trim(); 45 | } 46 | } else { 47 | // Handle parameters without type hints 48 | const parts = param.split('=').map(p => p.trim()); 49 | result.name = parts[0].split(':')[0].trim(); 50 | if (parts[1]) { 51 | result.default = parts[1]; 52 | } 53 | } 54 | 55 | return result; 56 | }); 57 | } 58 | return []; 59 | } 60 | 61 | /** 62 | * @param {vscode.ExtensionContext} context 63 | */ 64 | function activate(context) { 65 | console.log('CARLA API Completion extension is now active!'); 66 | 67 | apiDefinition = loadApiDefinition(context.extensionPath); 68 | if (!apiDefinition) { 69 | return; 70 | } 71 | 72 | const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); 73 | statusBarItem.text = "CARLA API Ready"; 74 | statusBarItem.tooltip = "CARLA API completion is active"; 75 | statusBarItem.show(); 76 | context.subscriptions.push(statusBarItem); 77 | 78 | // Register completion provider with context awareness 79 | const completionProvider = vscode.languages.registerCompletionItemProvider( 80 | 'python', 81 | { 82 | provideCompletionItems(document, position) { 83 | if (!apiDefinition) return []; 84 | 85 | const linePrefix = document.lineAt(position).text.substring(0, position.character); 86 | const completionItems = []; 87 | 88 | // Check if we're typing after a dot 89 | const dotMatch = linePrefix.match(/(\w+)\.\s*$/); 90 | if (dotMatch) { 91 | const className = dotMatch[1]; 92 | const classData = apiDefinition.classes[className]; 93 | 94 | if (classData) { 95 | // Add methods for this specific class 96 | for (const methodName in classData.methods) { 97 | const methodData = classData.methods[methodName]; 98 | const methodItem = new vscode.CompletionItem( 99 | methodName, 100 | vscode.CompletionItemKind.Method 101 | ); 102 | 103 | // Add method documentation 104 | methodItem.documentation = new vscode.MarkdownString() 105 | .appendCodeblock(methodData.signature || methodName + '()', 'python') 106 | .appendMarkdown('\n\n' + (methodData.docstring || 'No documentation available')); 107 | 108 | // Add parameter snippets 109 | if (methodData.signature) { 110 | const params = parseMethodSignature(methodData.signature); 111 | if (params.length > 0) { 112 | methodItem.insertText = new vscode.SnippetString( 113 | `${methodName}(${params.map((p, i) => `\${${i + 1}:${p.name}}`).join(', ')})` 114 | ); 115 | } 116 | } 117 | 118 | methodItem.sortText = '1' + methodName; 119 | completionItems.push(methodItem); 120 | } 121 | 122 | // Add properties for this specific class 123 | for (const propName in classData.properties) { 124 | const propData = classData.properties[propName]; 125 | const propItem = new vscode.CompletionItem( 126 | propName, 127 | vscode.CompletionItemKind.Property 128 | ); 129 | 130 | const access = []; 131 | if (propData.readable) access.push('Read'); 132 | if (propData.writable) access.push('Write'); 133 | 134 | propItem.documentation = new vscode.MarkdownString() 135 | .appendMarkdown(`**${access.join('/')} Property**\n\n`) 136 | .appendMarkdown(propData.docstring || 'No documentation available'); 137 | 138 | propItem.sortText = '2' + propName; 139 | completionItems.push(propItem); 140 | } 141 | } 142 | } else { 143 | // Only show class completions when not typing after a dot 144 | for (const className in apiDefinition.classes) { 145 | const classData = apiDefinition.classes[className]; 146 | const item = new vscode.CompletionItem(className, vscode.CompletionItemKind.Class); 147 | item.documentation = new vscode.MarkdownString(classData.docstring || `CARLA ${className} class`); 148 | item.sortText = '0' + className; 149 | completionItems.push(item); 150 | } 151 | } 152 | 153 | return completionItems; 154 | } 155 | }, 156 | '.' // Trigger completion on dot 157 | ); 158 | 159 | // Register signature help provider 160 | const signatureProvider = vscode.languages.registerSignatureHelpProvider( 161 | 'python', 162 | { 163 | provideSignatureHelp(document, position) { 164 | const lineText = document.lineAt(position).text; 165 | const linePrefix = lineText.substring(0, position.character); 166 | 167 | // Find the method call being typed 168 | const methodMatch = linePrefix.match(/(\w+)\.(\w+)\s*\(/); 169 | if (!methodMatch) return null; 170 | 171 | const [_, className, methodName] = methodMatch; 172 | const classData = apiDefinition.classes[className]; 173 | if (!classData || !classData.methods[methodName]) return null; 174 | 175 | const methodData = classData.methods[methodName]; 176 | const params = parseMethodSignature(methodData.signature); 177 | 178 | const signatureHelp = new vscode.SignatureHelp(); 179 | const signature = new vscode.SignatureInformation( 180 | methodData.signature, 181 | new vscode.MarkdownString(methodData.docstring) 182 | ); 183 | 184 | // Add parameter information 185 | signature.parameters = params.map(param => { 186 | const label = param.type ? 187 | `${param.name}: ${param.type}` : 188 | param.name; 189 | 190 | const documentation = new vscode.MarkdownString() 191 | .appendMarkdown(`Parameter: \`${param.name}\`\n\n`) 192 | .appendMarkdown(param.type ? `Type: \`${param.type}\`\n\n` : '') 193 | .appendMarkdown(param.default ? `Default: \`${param.default}\`\n\n` : ''); 194 | 195 | return new vscode.ParameterInformation(label, documentation); 196 | }); 197 | 198 | signatureHelp.signatures = [signature]; 199 | signatureHelp.activeSignature = 0; 200 | signatureHelp.activeParameter = Math.max(0, 201 | (linePrefix.match(/,/g) || []).length 202 | ); 203 | 204 | return signatureHelp; 205 | } 206 | }, 207 | '(', ',' 208 | ); 209 | 210 | // Register hover provider 211 | const hoverProvider = vscode.languages.registerHoverProvider( 212 | 'python', 213 | { 214 | provideHover(document, position) { 215 | if (!apiDefinition) return null; 216 | 217 | const range = document.getWordRangeAtPosition(position); 218 | if (!range) return null; 219 | 220 | const word = document.getText(range); 221 | 222 | if (apiDefinition.classes[word]) { 223 | const classData = apiDefinition.classes[word]; 224 | return new vscode.Hover( 225 | new vscode.MarkdownString() 226 | .appendMarkdown(`**CARLA Class: ${word}**\n\n`) 227 | .appendMarkdown(classData.docstring || 'No documentation available') 228 | .appendMarkdown('\n\nBase classes: ' + classData.base_classes.join(', ')) 229 | ); 230 | } 231 | 232 | const lineText = document.lineAt(position.line).text; 233 | const dotIndex = lineText.lastIndexOf('.', position.character); 234 | if (dotIndex > 0) { 235 | const className = lineText.substring(0, dotIndex).trim().split(' ').pop(); 236 | const classData = apiDefinition.classes[className]; 237 | 238 | if (classData) { 239 | if (classData.methods[word]) { 240 | const methodData = classData.methods[word]; 241 | return new vscode.Hover( 242 | new vscode.MarkdownString() 243 | .appendMarkdown(`**Method: ${className}.${word}**\n\n`) 244 | .appendCodeblock(methodData.signature || '', 'python') 245 | .appendMarkdown('\n\n' + (methodData.docstring || 'No documentation available')) 246 | ); 247 | } 248 | 249 | if (classData.properties[word]) { 250 | const propData = classData.properties[word]; 251 | return new vscode.Hover( 252 | new vscode.MarkdownString() 253 | .appendMarkdown(`**Property: ${className}.${word}**\n\n`) 254 | .appendMarkdown(propData.docstring || 'No documentation available') 255 | ); 256 | } 257 | } 258 | } 259 | 260 | return null; 261 | } 262 | } 263 | ); 264 | 265 | context.subscriptions.push(completionProvider, signatureProvider, hoverProvider); 266 | } 267 | 268 | function deactivate() {} 269 | 270 | module.exports = { 271 | activate, 272 | deactivate 273 | } --------------------------------------------------------------------------------