{"id":34097389,"url":"https://github.com/firedotguy/pyxend","last_synced_at":"2026-04-25T03:35:04.809Z","repository":{"id":308001697,"uuid":"1031280184","full_name":"firedotguy/pyxend","owner":"firedotguy","description":"Write Visual Studio Code extensions in Python — no JavaScript needed. Define commands with decorators, access editor context, and modify files, all using pure Python.","archived":false,"fork":false,"pushed_at":"2025-08-21T14:29:43.000Z","size":3252,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-16T20:50:02.477Z","etag":null,"topics":["cli","extension-vscode","javascript","library","python","vscode"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/firedotguy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-03T12:09:32.000Z","updated_at":"2025-08-21T13:53:33.000Z","dependencies_parsed_at":null,"dependency_job_id":"05df05ca-fde6-4626-906b-ed97f71ace64","html_url":"https://github.com/firedotguy/pyxend","commit_stats":null,"previous_names":["codeflane/pyxend","firedotguy/pyxend"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/firedotguy/pyxend","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firedotguy%2Fpyxend","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firedotguy%2Fpyxend/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firedotguy%2Fpyxend/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firedotguy%2Fpyxend/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/firedotguy","download_url":"https://codeload.github.com/firedotguy/pyxend/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firedotguy%2Fpyxend/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32249047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-25T03:17:44.950Z","status":"ssl_error","status_checked_at":"2026-04-25T03:16:45.208Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","extension-vscode","javascript","library","python","vscode"],"created_at":"2025-12-14T15:54:48.407Z","updated_at":"2026-04-25T03:35:04.796Z","avatar_url":"https://github.com/firedotguy.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pyxend\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/pypi/v/pyxend\" alt=\"PyPI Version\"\u003e\n  \u003cimg src=\"https://img.shields.io/pypi/l/pyxend\" alt=\"License\"\u003e\n  \u003cimg src=\"https://img.shields.io/github/last-commit/codeFlane/pyxend\" alt=\"Last Commit\"\u003e\n  \u003cimg src=\"https://img.shields.io/github/stars/codeFlane/pyxend?style=social\" alt=\"GitHub Stars\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/VSC-Compatible-blueviolet\" alt=\"VS Code Compatible\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Language-Python-blue\" alt=\"Written in Python\"\u003e\n  \u003cimg src=\"https://static.pepy.tech/badge/pyxend\" alt=\"Downloads\"\u003e\n\u003c/p\u003e\npyxend is a Python-based framework and CLI tool for building Visual Studio Code extensions entirely in Python. It allows to define VS code extension commands using simple Python decorators and handle VS Code actions like modifying editor content, showing modals, and running terminal commands.\n\n\u003e ⚡️ No JavaScript required for extension logic — write VS Code extensions in pure Python.\n\n\u003e [!WARNING]\n\u003e This project is freezed/archived due i have no time. Maybe will continue work in summer.\n\n![Preview](https://raw.githubusercontent.com/codeFlane/pyxend/main/preview.gif)\n\u003e ⚠️ Note: Preview was recorded when the project was called pyvscode. Now project renamed to pyxend.\n---\n\n## ✨ Features\n\n- 🧠 Simple Python API for defining commands\n- ⚙️ CLI tool to scaffold, sync, build, and publish extensions\n- 🧩 Template-based generation of `extension.js` and `package.json`\n- 🔁 Context-aware Python execution with editor data (selected text, cursor, file)\n- 📦 Easy packaging using `vsce`\n\n---\n\n## 📦 Installation\n\n```bash\npip install pyxend\n```\nOr using git repository:\n```bash\ngit clone https://github.com/codeflane/pyxend\ncd pyxend\npip install -e .\n```\nMake sure Node.js and vsce are installed:\n```\nnpm install -g vsce\n```\n\n## 🚀 Getting Started\n### 1. Create a new extension\n```bash\npyxend init \"My Extension Name\" myextension\n```\n\n### 2. Add logic in Python\n\nEdit main.py:\n```python\nfrom pyxend import Extension, ModalType\n\next = Extension()\n\n@ext.command('hello')\ndef say_hello(ctx):\n    ext.show_modal(\"Hello from Python!\", type=ModalType.INFO)\n\next.run()\n```\n\n### 3. Sync the metadata\n```bash\npyxend sync\n```\n\n### 4. Build and install the extension\n```bash\npyxend build\ncode --install-extension your-extension.vsix\n```\n\n## 📚 CLI Options\nAll CLI commands accept a `--target` (or `-t`) option to specify the working directory (defaults to current folder).\n\n### Init\n```bash\npyxend init \"Display Name\" extension_name\n```\nInit new project.\n\n#### Arguments:\n - **Display Name:** extension display name (that showing in extension hub)\n - **Extension Name:** extension name (defaults to display name)\n\n#### Creates:\n - `main.py` (logic)\n - `extension.js` (bridge)\n - `package.json` (extension metadata)\n - `.vscodeignore`\n\n### Sync\n```bash\npyxend sync\n```\nSync Python decorators in main.py with `extension.js` and `package.json`\n\n### Metadata\n```bash\npyxend metadata -v 0.0.1 -e 1.70.0 -d desc -t title -n name -g git\n```\nUpdate package.json metadata\n\n#### Options:\n| Option               | Description                   |\n|----------------------| ------------------------------|\n| `--engine / -e`      | VS Code engine version        |\n| `--description / -d` | Description of your extension |\n| `--git / -g`         | GitHub repo URL               |\n| `--name / -n`        | Display name                  |\n| `--version / -v`     | Extension version             |\n\n### License\n```bash\npyxend license author\n```\nCreate LICENSE file (now only MIT support).\nLicense is required for creating extensions\n\n\n## 🧩 Extension API\nThe core API is exposed via the `Extension` class.\n\n### Command decorator\n\nDecorator to register a command that can be invoked from VS Code.\n\n#### Arguments:\n\n* `name` - The command name (e.g., `\"sayHello\"`).\n* `title` - Title to display in the Command Palette. Defaults to `name`\n\n#### Context:\n\nWhen the command is invoked, it receives a `context` dictionary with useful metadata:\n\n```json\n{\n  \"selected_text\": \"Hello\", // Currently selected text\n  \"language\": \"python\", // Opened file language\n  \"cursor_pos\": {\"line\": 3, \"character\": 15}, // Current cursor position\n  \"file_path\": \"D:/projects/example.py\", // Opened file path\n  \"all_text\": \"Hello World\", // File content\n  \"cursor_word\": \"Hello\", // the word under the cursor\n  \"lines\": 3, // Lines count in file\n  \"file_size\": 12, // File size in bytes\n  \"opened_files\": [\"D:/projects/example.py\", \"D:/test.txt\"], // Currently opened files\n  \"is_saved\": false, //Is file saved\n  \"workspace\": \"D:/projects\" //Opened workspace folder\n}\n```\n\n#### Example:\n\n```python\n@ext.command(\"sayHello\", title=\"Say Hello\")\ndef say_hello(context):\n    ext.show_modal(f\"Hi! You selected: {context['selected_text']}\")\n```\n---\n\n### Event decorator\nDecorator to register an event that can be invoked from VS Code.\n\n#### Arguments:\n\n* `event` - Event type (`Event` enum).\n\n#### Context:\nContext same as `Command decorator`. See pyxend -\u003e Extension API -\u003e Command decorator -\u003e Context\n\n#### Example:\n\n```python\n@ext.command(\"sayHello\", title=\"Say Hello\")\ndef say_hello(context):\n    ext.show_modal(f\"Hi! You selected: {context['selected_text']}\")\n```\n---\n\n### Show modal\nShow modal popup\n\n#### Arguments:\n - message - The message to display.\n - type - Must be one of the ModalType values:\n   - ModalType.INFO - modal with an blue informational (i) icon (default)\n   - ModalType.WARNING - modal with an yellow warning /!\\ icon\n   - ModalType.ERROR - modal with an red error (x) icon\n\n#### Example:\n```python\next.show_modal(\"This is an error\", type=ModalType.ERROR) #Show error modal with text \"This is an error\"\n```\n\n---\n### Replace selected text\nReplace the currently selected text in the editor. (deprecated)\n\n#### Arguments:\n* `text` - The text that will replace the current selection.\n\n#### Example:\n```python\next.replace_selected_text(\"Replaced content.\") #Replace currently selected text to \"Replace content.\"\n```\n\n---\n### Insert text\nInsert new text.\n\n#### Arguments:\n* `text` - The text to insert.\n* `preset` - Position preset. Must be one of the InsertTextPreset values:\n  * InsertTextPreset.START - Insert text at the start of file\n  * InsertTextPreset.CURSOR - Insert text after cursor position\n  * InsertTextPreset.CUSTOM - Insert text at custom position (use `line` and `character` to provide it) (default)\n  * InsertTextPreset.END - Insert text at the end of file\n\n* `line` - Line number to insert text. Requires only when preset is `CUSTOM`\n* `character` - Character number to insert text. Requires only when preset is `CUSTOM`\n\n#### Example:\n```python\next.insert_text(\"Inserted text.\", preset=InsertTextPreset.CURSOR) #Insert text \"Inserted text.\" after cursor position\n```\n\n---\n### Replace text\nReplace text.\n\n#### Arguments:\n* `text` - The text to replace.\n* `preset` - Position preset. Must be one of the ReplaceTextPreset values:\n  * ReplaceTextPreset.SELECTED - Replace selected text\n  * ReplaceTextPreset.CUSTOM - Replace text at custom position (use `start_line`, `start_character`, `end_line` and `end_character` to provide it) (default)\n  * ReplaceTextPreset.ALL - Replace whole file\n\n* `start_line` - Start line number to replace text. Requires only when preset is `CUSTOM`\n* `start_character` - Start character number to replace text. Requires only when preset is `CUSTOM`\n* `end_line` - End line number to replace text. Requires only when preset is `CUSTOM`\n* `end_character` - End character number to replace text. Requires only when preset is `CUSTOM`\n\n#### Example:\n```python\next.replace_text(\"Replaceed text.\", preset=InsertTextPreset.ALL) #Replace all file text to \"Replaced text.\"\n```\n\n---\n### Open file\nOpen a file in the editor by its path.\n\n#### Arguments:\n* `path` - Full path to the file.\n\n#### Example:\n```python\next.open_file(\"D:/projects/example.py\") #open \"D:/projects/example.py\" in editor\n```\n\n---\n### Set cursor position\nMove the editor’s cursor to the specified position.\n\n#### Arguments:\n* `line` - Line number.\n* `character` - Character number.\n\n#### Example:\n```python\next.set_cursor_pos(5, 10) #move cursor to line 5, character 10\n```\n\n---\n### Save file\nSave the current file.\n\n#### Example:\n```python\next.save_file() #save current file\n```\n\n---\n### Replace all text\nReplace the entire content of the file. (deprecated)\n\n#### Arguments:\n* `text` - The new content for the whole file.\n\n#### Example:\n```python\next.replace_all_text(\"print('Hello, World!')\\n\") #replace all file text to \"print('Hello, World!')\"\n```\n\n---\n### Run terminal command\nExecute a command in a new or existing terminal.\n\n#### Arguments:\n* `command` - The terminal command to execute.\n* `name` (optional) - Name of the terminal instance. Default is \"pyxend terminal\"\n\n#### Example:\n```python\next.run_terminal_command(\"echo 'Hello World'\") #create new terminal and echo \"Hello World\"\n```\n\n---\n### Delete selected text\nDelete currently selected text\n\n#### Example\n```python\next.delete_selected_text() #delete selected text\n```\n\n---\n### Delete file\nDelete currently opened file (Do not recommend to use)\n\n#### Example\n```python\next.delete_file() #delete file\n```\n\n---\n### Status message\nShow status message in a bottom of screen.\n\n#### Arguments:\n* `message` - The message to show.\n* `timeout` (optional) - How long message will show in ms. Defaults to 3000ms (3s)\n\n#### Example:\n```python\next.status_message(\"Hello from pyxend\", 1000) #show status message \"Hello from pyxend\" for 1 second\n```\n\n---\n## ⚠️ Important Notes about Command Execution\n\n* All actions (`ext.show_modal`, `ext.insert_text`, etc.) are collected into a list during Python execution and **returned as a single JSON batch** to VS Code.\n* This means **VS Code does not execute Python actions one-by-one**. It only runs Python once, receives all the actions at once, and **then executes them sequentially in JavaScript**.\n* Any delay (`time.sleep`) or conditional logic in Python will **happen before any action is performed** in the editor.\n\n### Example:\n\n```python\next.show_modal(\"First\")\ntime.sleep(1)\next.show_modal(\"Second\")\n```\n\nThis will result in **both modals appearing immediately**, one after the other — not with a delay between them.\n\n---\n\n### 🚧 Future Plans\n\nWe are planning to add **streaming or asynchronous action execution** in a future version (`v1.0` or `v2.0`) so that:\n\nactions like `ext.show_modal()` can be executed live, one at a time, and delays or dynamic logic will reflect in real-time in the editor.\n\nWe already have some ideas on how to implement this — stay tuned!\n\n## 🧠 How it Works\n\n`pyxend` bridges VS Code and Python.\nWhen a command is executed:\n\n1. **VS Code (JavaScript)**\n\n   * Collects the file context (selected text, full code, cursor, file path, etc.)\n   * Launches the Python script (`main.py`) and passes the command name and context as JSON.\n\n2. **Python (pyxend)**\n\n   * Receives the command and context.\n   * Executes the matching `@ext.command(...)` function.\n   * Generates actions list from executed commands.\n   * Return actions list to the JS.\n\n3. **VS Code (JavaScript)**\n\n   * Parses the returned actions.\n   * Executes them one by one using the VS Code API (editing text, opening files, setting cursor position, etc.)\n\nThis allows Python to control editor behavior dynamically.\n\n## 🔧 How to Integrate a New Custom Action\n\nTo add a new custom action that isn’t supported yet:\n\n### 1. Define it in Python\n\nAppend an action manually:\n\n```python\next.actions.append({\n    \"action\": \"highlight_range\",\n    \"line_start\": 5,\n    \"line_end\": 8\n})\n```\n\n### 2. Extend the `extension.js`\n\nOpen `extension.js` and add a new case to handle it:\n\n```js\ncase \"highlight_range\":\n  if (!editor) return;\n  const start = new vscode.Position(action.line_start, 0);\n  const end = new vscode.Position(action.line_end, 0);\n  const decorationType = vscode.window.createTextEditorDecorationType({\n    backgroundColor: \"rgba(255,255,0,0.2)\"\n  });\n  editor.setDecorations(decorationType, [new vscode.Range(start, end)]);\n  break;\n```\n\nThis allows `pyxend` to be fully extensible.\n\u003e Note: after syncing (`pyxend sync`), all JS will overwrite. It will be fixed in future versions.\n\n## 📄 Changelog\nSee full change log in [CHANGELOG.md](./CHANGELOG.md)\n\n### 0.3.0 (Latest)\nAdded events and 2 new actions\n\n### 0.2.0\nAdded 2 new actions and reworked replace/insert text methods\n\n### 0.1.2\nAdded 3 new values in context, renamed `manifest` → `metadata`\n\n### 0.1.1\nFixed packaging bug, improved error modals, typo fixes\n\n## ⭐ Contributing\nThank you for checking out pyxend!\nIf you find it useful, please consider:\n\n - ⭐ Starring the GitHub repository — it really helps the project grow.\n - 🛠 Opening an issue or PR with your suggestions or improvements.\n - 📢 Sharing the project with fellow Python developers who want to build VS Code extensions without touching JavaScript.\n\n\u003e Let’s make Python-powered VS Code extensions mainstream!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffiredotguy%2Fpyxend","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffiredotguy%2Fpyxend","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffiredotguy%2Fpyxend/lists"}