Repository: vlang/vscode-vlang Branch: master Commit: cc6dee79af1f Files: 41 Total size: 76.2 KB Directory structure: gitextract_z3ekfbry/ ├── .editorconfig ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ ├── ci.yml │ └── docs_ci.yml ├── .gitignore ├── .prettierrc.json ├── .vscode/ │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── eslint.config.mjs ├── language-configuration.json ├── package.json ├── snippets/ │ └── snippets.json ├── src/ │ ├── commands.ts │ ├── exec.ts │ ├── extension.ts │ ├── langserver.ts │ ├── logger.ts │ └── utils.ts ├── syntaxes/ │ ├── tests/ │ │ ├── accessor.v │ │ ├── comma.v │ │ ├── comparison.v │ │ ├── dot.int.v │ │ ├── escape.v │ │ ├── function.v │ │ ├── hashtag.v │ │ ├── method.v │ │ ├── numbers.v │ │ ├── optional.v │ │ ├── pubfn.v │ │ ├── string.v │ │ ├── type.v │ │ └── variable.v │ ├── v.mod.tmLanguage.json │ └── v.tmLanguage.json └── tsconfig.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = tab insert_final_newline = true max_line_length = 90 trim_trailing_whitespace = true [*.{yml,yaml}] indent_style = space indent_size = 2 ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "npm" directory: "/" schedule: interval: "weekly" ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: [push, pull_request] jobs: build-and-package: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node-version: "24" - name: Install dependencies run: npm install - name: Build run: npm run build - name: VSCE package run: npm run package code-style: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node_version: "24" - name: Install dependencies run: npm install - name: Run eslint run: npm run lint grammar-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node_version: "24" - name: Install dependencies run: npm install - name: Run grammar tests run: npm run test:grammar ================================================ FILE: .github/workflows/docs_ci.yml ================================================ name: Docs CI on: [push, pull_request] jobs: markdown-lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node-version: "24" - name: Install dependencies run: npm install - name: Check readme linting run: npm run lint:md ================================================ FILE: .gitignore ================================================ .vscode/ipch *.code-workspace *.exe *.tmp.json # MacOS .DS_Store *.dSYM/ # Node **/node_modules/ **/out/ **/*.tsbuildinfo **/*.vsix ================================================ FILE: .prettierrc.json ================================================ { "$schema": "https://json.schemastore.org/prettierrc", "semi": false, "singleQuote": false, "printWidth": 100 } ================================================ FILE: .vscode/extensions.json ================================================ { "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] } ================================================ FILE: .vscode/launch.json ================================================ { "version": "0.2.0", "configurations": [ { "type": "extensionHost", "request": "launch", "name": "Launch Extension", "runtimeExecutable": "${execPath}", "args": ["--extensionDevelopmentPath=${workspaceFolder}"], "outFiles": ["${workspaceFolder}/out/**/*.js"], "preLaunchTask": "Build Extension" } ] } ================================================ FILE: .vscode/settings.json ================================================ // Place your settings in this file to overwrite default and user settings. { "files.exclude": { "out": false // set this to true to hide the "out" folder with the compiled JS files }, "search.exclude": { "out": true // set this to false to include "out" folder in search results }, "editor.defaultFormatter": "esbenp.prettier-vscode" } ================================================ FILE: .vscode/tasks.json ================================================ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format { "version": "2.0.0", "tasks": [ { "label": "Build Extension in Background", "group": "build", "type": "npm", "script": "watch", "problemMatcher": { "base": "$tsc-watch" }, "isBackground": true }, { "label": "Build Extension", "group": "build", "type": "npm", "script": "build", "problemMatcher": { "base": "$tsc" } } ] } ================================================ FILE: .vscodeignore ================================================ .vscode/** .vscode-test/** # Node / npm node_modules/ package-lock.json # Source and build outputs src/ build/ *.vsix # TypeScript build artifacts tsconfig.json tsconfig.*.json tsconfig.tsbuildinfo # Images and bundled assets images/ # Test and CI tests/** test/** **/tests **/*.spec.* **/*.test.* coverage/** # Configuration and metadata .github/** .eslintrc* .eslintignore .prettierrc* .prettierignore .editorconfig # Misc .gitignore .v .go .yarn* *.log .vscodeignore ================================================ FILE: CHANGELOG.md ================================================ # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## 0.2.0 _13 October 2025_ ### Features - ⏫ Update extension to prompt to install v and vls if not found - ⏫ Use the new vls (https://github.com/vlang/vls) - ⏫ Add syntax support for v.mod files ## 0.1.14 _1 September 2022_ ### Features - ℹ️ VLS installation and server launch is now handled by `v ls` (thanks @nedpals #450) ### Fixes - Fix `defer` sniffet (thanks @StunxFS #467) - Fix syntax highlighting `unsafe` and `callconv` attributes (thanks @StunxFS #468) ## 0.1.13 _17 May 2022_ ### Fixes - 🐛 Fix compiling VLS using `v run build.vsh` (thanks @nedpals) ## 0.1.12 _12 May 2022_ ### Fixes - 🐛 Fix syntax highlighting. (thanks @danieldaeschle #331, #304 #373) ## 0.1.11 _12 November 2021_ ### Fixes - 🐛 Fix critical bug when launching / stopping VLS process. (thanks @nedpals #337) - 🐛 Fix launching VLS process on TCP after "Remote Server" was disabled. ## 0.1.10 _3 October 2021_ ### Features - ℹ️ VLS has now support for connecting via TCP! (thanks @nedpals #283) - 🔄 Added dialog when updating settings related to VLS (thanks @nedpals #283) - ℹ️ Added custom CLI arguments setting that can be passed to the VLS executable (thanks @nedpals #302) ### Fixes - 🐛Fix syntax highlighting for numeric methods (e.g. `.int()`) (thanks @pouyakary #281) - 🐛Fix comma not identified by the grammar (thanks @pouyakary #282) - ⏫ Improved VLS connection flow (thanks @nedpals #283) - ⏫ Fix / update VLS compilation command (thanks @nedpals #303) - ⏫ Fix VLS restart command (thanks @nedpals #303 #310) ## 0.1.9 _11 August 2021_ ### Features - 🔄 You can now update or restart the language server without restarting VSCode! (Press `Ctrl+Shift+P` and select `V: Update VLS` or `V: Restart VLS`) (thanks @carterisonline #239) - ⏫ Add more settings for VLS including support for custom VROOT path and debug mode setting (thanks @nedpals #271) - ⏫ v.mod files are now syntax highlighted! (thanks @serkonda7). - ⏫ Accessors, `size_t` and option symbol (`?`) are now properly syntax highlighted! (thanks @pouyakary #245 #248 #249) - ℹ️ Added more helpful information when encountering VLS installation errors. - 🚮 Removed deprecated commands including for testing and showing help information. ### Fixes - 🐛Fixed "Open current code on DevBits V playground" command showing on non-V files. - 🐛Fixed syntax highlighting underline-separated numbers (e.g `1_000`). - Simplification of the URL opening mechanism when opening DevBits Playground. - 🐛Fixed syntax highlighting for string literals and hash directives (e.g `#include`) (#244) - 🐛Fixed syntax highlighting for float exponents. ### Internal / Infrastructure Changes - Build system was migrated from Webpack to ESBuild resulting ~5x faster builds. - Added ESLint integration. - Added unit tests for syntax highlighting. - Added CI for running grammar tests. ## 0.1.8 _25 March 2021_ ### Features - ⏫ You can update vls by a vscode command! Just press Ctrl+Shift+P and type `update vls`. That's it! - Support for enabling feature using flags (thanks @nedpals) - Highlight for #define and #pkgconfig (thanks @crackedmind #213) - Update snippets to the current syntax (thanks @StunxFS #218) - Improved syntax support (thanks @AliChraghi #221 #223) ### Fixes - 🐛Fixes installing vls automatically (#224) ## 0.1.7 _9 January 2021_ ### Features - ⏫ Updated language client package. - 📩 Newest Version on vscode marketplace! ### Fixes - 🐛 Fixes syntax highlight for struct. ## 0.1.6 _26 December 2020_ ### Features - ⏫ Updated typescript version to 4.1. - 🔄 Progress notification when installing vls. ### Fixes - 🐛 Fixes bug on windows where executable path was without `.exe` suffix. ## 0.1.5 _24 December 2020_ ### Features - ⬇️ Automatically install vls (keep in mind that vls is still alpha)! - 🔄 Disable and enable vls on the fly ### Fixes - 🚮 Removed unused and old lint & fmt functionality which is now done by the vls! - 🐛 Fixes `#include` keyword highlighting ## 0.1.4 _12 December 2020_ ### Features - 🔴 Breakpoints are now part of the party! ### Fixes - 👨🏼 Updated publisher name. - 🌐 Updated URLs in package.json. - Union is now recognized as a keyword. ## 0.1.2 _17 April 2020_ ### Added - Added region folding support [13084c1](https://github.com/vlang/vscode-vlang/commit/13084c158e981ec9983e86f7637c403e653d140f) - Added highlighting for `flag` attribute [ec2bffa](https://github.com/vlang/vscode-vlang/commit/ec2bffa670d7761267026f4cb5c1bf620e12e81e) - Added binary, octal, exponental highlighting [6b58431](https://github.com/vlang/vscode-vlang/commit/6b58431cd51cb4449924aece54998d5b0751c4a1) - Added highlighting for `is`, `var` keywords [172ecae](https://github.com/vlang/vscode-vlang/commit/172ecae2849a551c8b0c04d7d3eb04dcb94b135c) ### Changed - Fixed invalid pattern for standart numeric types [8fd5e7e](https://github.com/vlang/vscode-vlang/commit/8fd5e7ec6867d99c04b1662503f65e512f02aa67) - Fixed #include VALUE bug [b290d2d](https://github.com/vlang/vscode-vlang/commit/b290d2d074d2150079a4dbb78367412d5a38bdba) - Fixed saving error [6a85e45](https://github.com/vlang/vscode-vlang/commit/6a85e45e6509ac2217f68190a4693ff2134c0dd3) - Fixed column of error [dd4c11d](https://github.com/vlang/vscode-vlang/commit/dd4c11daa03ce268681be64eefcfd615e0814ced) - Fixed error message filepath [fc526f9](https://github.com/vlang/vscode-vlang/commit/fc526f96f4743d0bb9ff16b79d32e50b24c1f79c) - Fixed incorrect struct highlighting with variable name [3b682a9](https://github.com/vlang/vscode-vlang/commit/3b682a9e31ec72257e351510be77126474921834) ## 0.1.1 _16 January 2020_ ### Added - Linter [35d9805](https://github.com/vlang/vscode-vlang/commit/35d9805cdadb49335de70484b5bf1815f356857f) - Implemented "Show Version Info" [28420de](https://github.com/vlang/vscode-vlang/commit/28420dee18c6c52050a29a7a8bde648bafed85f0) - Implemented "Build an optimized executable from current file" [37e5049](https://github.com/vlang/vscode-vlang/commit/37e50499e38552b1d025ab4c3ada3ad6a30c6113) - Snippet for `charptr` [503f796](https://github.com/vlang/vscode-vlang/commit/503f796e2f5ac372c023c119525b1fa8cd580a97) - Added `unsafe` keyword, `typedef` attribute [f873252](https://github.com/vlang/vscode-vlang/commit/f873252d43422d9d1317ce735f31c158a523afe2) ### Changed - Fixed inconsistent `struct` highlighting [3170227](https://github.com/vlang/vscode-vlang/commit/31702271d55313ac97b17433111465ee74d3902d) - Replaced VSCode deprecated API with new API [6f829d9](https://github.com/vlang/vscode-vlang/commit/6f829d9469be9202aa331abb46479e362c9d43bd) ### Removed - Removed icon theme [827171b](https://github.com/vlang/vscode-vlang/commit/827171bb0c4eca127a6e90a8b92f9de8ebdf68a9) ## 0.0.9 _30 December 2019_ ### Added - Highlighting for `as` keyword [e7c72b2](https://github.com/vlang/vscode-vlang/commit/e7c72b2cb23444d5c1fa5e5aa2f61e64eaa8264f) - Highlighting for `charptr` keyword [b9f16bc](https://github.com/vlang/vscode-vlang/commit/b9f16bce1e8089d0b2b2dd50bf09ff8aec621122) - Support for `.vsh` [e79a22e](https://github.com/vlang/vscode-vlang/commit/e79a22e72dabeca2cc26e08829e6da6f1a957e3c) - Some more snippets [b06ae81](https://github.com/vlang/vscode-vlang/commit/b06ae81b47ec6354ef1ed887ce6357ef03cd712c) ### Changed - Fixed invalid icon theme [be3fcb3](https://github.com/vlang/vscode-vlang/commit/be3fcb399a309d52e8869f6ac9067aa454dd3b8a) - Fixed `vfmt` [3522196](https://github.com/vlang/vscode-vlang/commit/3522196890c4f89da2f173684fe326e79fbb4c52) - Cleaned up resource usage [4f587ed](https://github.com/vlang/vscode-vlang/commit/4f587ed1cbcd6e884da250528ba7f2e0728127cb) - Removed unused entries from `.travis.yml` [96e1a0b](https://github.com/vlang/vscode-vlang/commit/96e1a0b06946d2659d5e92242aeabbfc56faf909) ## 0.0.8 _20 October 2019_ ### Added - Highlighting for attributes. [f85aec5](https://github.com/vlang/vscode-vlang/commit/f85aec57a46116204c9f3fbe370277907ff00a9c) - Highlighting for `${...}` syntax [f11581d](https://github.com/vlang/vscode-vlang/commit/f11581dcaaadb88da2130a4d9b444d4281f1c0d4) - Highlighting for `none` keyword. [d682dbe](https://github.com/vlang/vscode-vlang/commit/d682dbefb6330b9383d849334da7677d6f6cf2d6) ### Changed - Fixed nested comments. [f19d486](https://github.com/vlang/vscode-vlang/commit/f19d4868dd34a729bee01441eb62c6a59a16a1e6) - Insert tabs instead of spaces. [f4525ca](https://github.com/vlang/vscode-vlang/commit/f4525ca1eb3d514eeb2bb2956724dc18a2645235) - Corrupted icon. [beeb022](https://github.com/vlang/vscode-vlang/commit/beeb0223c03a1a40b976ef350d546282b3cfa8ff) - Infinity recursion in certain grammar patterns [a40e951](https://github.com/vlang/vscode-vlang/commit/1638585f838e30c2587eaf9ee8a08c28785b6f42) ## 0.0.7 _12 August 2019_ ### Added - New demos [636c358](https://github.com/vlang/vscode-vlang/commit/636c358eb53104f0b3f42f214305f9ef10fb9599) - New badges [ab94ea7](https://github.com/vlang/vscode-vlang/commit/ab94ea75950a59a5832cb6a6f32e6e8d5197e63a) ### Changed - Fixed function declaration from new line [cede5204](https://github.com/vlang/vscode-vlang/commit/cede52044e7acd56f880b0729dc3280c16d4c3e9) - Fixed invalid function space pattern [88477c2](https://github.com/vlang/vscode-vlang/commit/88477c24709836dd8e7d5fdd01d0f729870c278b) - Fixed import, module (s) bag [ef56b2c](https://github.com/vlang/vscode-vlang/commit/ef56b2c8020d7b6d4d5408635339fa29265ad216) ### Removed - Old demos [636c358](https://github.com/vlang/vscode-vlang/commit/636c358eb53104f0b3f42f214305f9ef10fb9599) - testv.tmLanguage.json [4e3a353](https://github.com/vlang/vscode-vlang/commit/4e3a35358d7927efbd47b25911b50e9ad3ee1cd2) - Themes for prefering used defined themes [ef56b2c](https://github.com/vlang/vscode-vlang/commit/ef56b2c8020d7b6d4d5408635339fa29265ad216) ## 0.0.6 _15 July 2019_ ### Added - Metadata properties [37dd64b](https://github.com/vlang/vscode-vlang/commit/37dd64bcaf1a7799260d29773f55bf23f5f28247) - Ignore for specify files [45fbdd9](https://github.com/vlang/vscode-vlang/commit/45fbdd952a7c8dc6e971f52388b9629c9fd6ba4e) - Pattern for reference [b495745](https://github.com/vlang/vscode-vlang/commit/b495745e4354aee7d609adef164fc48be3a75d7e) ### Fixed - Invalid pattern for `ustring` [f7f32d1](https://github.com/vlang/vscode-vlang/commit/f7f32d108f2aa031b8335073ef77ab774a77f284) - Travis support [d1931ed](https://github.com/vlang/vscode-vlang/commit/d1931ed55b42161f6bd1df023685c1d060471165) - Invalid pattern for `variable-assignment` [c2ad846](https://github.com/vlang/vscode-vlang/commit/c2ad846e79aed3e5c4add8ee2e48aa3d20f18607) - `#include` pattern [ecf50c0](https://github.com/vlang/vscode-vlang/commit/ecf50c0a830923090b6f13700e8baca9bc3c3c86) ### Changed - types/vscode version to 1.20.0 [37dd64b](https://github.com/vlang/vscode-vlang/commit/37dd64bcaf1a7799260d29773f55bf23f5f28247) ### Removed - Autoclosed multilines comments (block) [012e640](https://github.com/vlang/vscode-vlang/commit/012e640a84772162a7d822c3b87890c20244fa78) ## 0.0.5 _30 June 2019_ ### Added - Pattern for static type `intptr` - Pattern for control keyword `$else` - Pattern for builtin casting/control function ([f877c3b](https://github.com/vlang/vscode-vlang/commit/f877c3b844564125431f9bd4accda0b4924f5f6c)). - String placeholder, escaped characters. - Auto closed multiline comments ([b173e1e](https://github.com/vlang/vscode-vlang/pull/8)) - Launch script for debuggin ([24b183a](https://github.com/vlang/vscode-vlang/commit/24b183aa79964962a1e6083ac5847a207935629b)) - Added two commands `v.ver, v.prod` ([d1d99a9](https://github.com/vlang/vscode-vlang/commit/d1d99a9806f9ffbbe235974f153fa837f2eb6b3b)) - Added TypeScript based project ([9fa4992](https://github.com/vlang/vscode-vlang/commit/9fa4992a7f549351c97d17b1ff95c94970e74bb3)) - Created `package-lock.json` ([16114d6](https://github.com/vlang/vscode-vlang/commit/16114d69ece533c217a0153655a2796c717fd02c)) ### Fixed - Invalid pattern for new-exist-extend-limited-overloaded functions ([8952a71](https://github.com/vlang/vscode-vlang/commit/8952a717ecd2683cfc69caca52f232a5540cd2b5)) - Invalid pattern for `module, import, #include` - Invalid pattern for `enum, type, struct, interface` ([83e27e0](https://github.com/vlang/vscode-vlang/commit/83e27e0e64a4a51414ec8ed80dbc6f03fb8bb517)) - Invalid typo `ligth` to `light` ([09b5257](https://github.com/vlang/vscode-vlang/commit/09b5257c7e0d4e10735d3c23d9cfa2eb27735dab)) - Invalid pattern for variable assignment. ## 0.0.4 _22 June 2019_ ### Added - Pattern for static types `byteptr, voidptr, ustring` - Pattern for extend (extra) function syntax `fn (a mut Vector) Set() {}` - Pattern for limited operator overloading `fn (a Operand) + (b Operand)Operand {}` - String placeholder. - String escaped characters. - Highlighting for V compiler headers without open source code **`.vh`** ### Fixed - Invalid pattern for floating point numbers. - Invalid pattern for single, double strings. - Invalid pattern for new function declaration. - Invalid pattern for exist function. - Invalid patterns for `module, import, #include, #flag` - Invalid pattern for generic `` - Invalid pattern for variable assignment. - Invalid pattern for label (conflict with default keyword) **`default:`** - Included pattern for variable increment, decrement. ## 0.0.3 _16 June 2019_ ### Added - Pattern for generics. - Generic highlighting. - Assignment operators `&=, |=, ^=, &&=, ||=, >>=, <<=`. ### Fixed - Invalid pattern for float numeric. - Invalid pattern for new/exist function. ## 0.0.2 _12 June 2019_ ### Added - Pattern for new-function variables, punctuation characters. - Pattern for exist-function punctuation characters. - Pattern for arithmethic, relation, logical, bitwise, assignment operators. ### Fixed - Invalid patterns for assignment operator. - Invalid patterns for integer, float, hex numerics. - Invalid patterns for new/exist function arguments. ### Changed - Highligting for `module, import, struct, enum, interface` from `default` to `bold underline`. ## 0.0.1 - 2019-06-10 _10 June 2019_ ### Added - Code snippets for standart keywords and expressions. - Developer dark theme for **V**. - TextMate Language Support for **V**. - Icons in `/icons` folder. - Images in `/images` folder. - Icon theme in `/theme/icon-theme.json`. - Icon for `.v` based files in `theme/images/v.svg`. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2019 0x9ef Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # V language support for Visual Studio Code [![Version](https://img.shields.io/visual-studio-marketplace/v/vlanguage.vscode-vlang.svg)](https://marketplace.visualstudio.com/items?itemName=vlanguage.vscode-vlang) [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/vlang/vscode-vlang/ci.yml?branch=master)](https://github.com/vlang/vscode-vlang/actions/) Provides [V language](https://vlang.io) support for Visual Studio Code. ## Preview ![First demo screenshot](./images/demo.png) ## Features ### Code Editing - syntax highlighting - code snippets for quick coding ## Usage First you will need to install [Visual Studio Code][vs-code] >= `1.105`. In the command palette (`Cmd+Shift+P`) select `Install Extensions` and choose `V`. Alternatively you can install the extension from the [Marketplace][market-ext-link]. Now open any `.v`, `.vsh`, `.vv` file in VS Code. _Note_: It is recommended to turn `Auto Save` on in Visual Studio Code (`File -> Auto Save`) when using this extension. ## Commands - `V: Run current file` - `V: Format current file` - `V: Build an optimized executable from current file` - `V: Show V version` - `V: Update VLS` - `V: Restart VLS` You can access all of the above commands from the command palette (`Cmd+Shift+P`). ## Debug the extension Clone this repository and run `npm install` to install the dependencies. Then press `F5` to open a new VS Code window with the extension loaded. Open the output console (`Cmd+Shift+U`) to see the debug output from the extension. Run `Cmd+Shift+P` and select `Preferences: Open User Settings` to update settings. ## License [MIT](./LICENSE) [vs-code]: https://code.visualstudio.com/ [market-ext-link]: https://marketplace.visualstudio.com/items?itemName=vlanguage.vscode-vlang ================================================ FILE: eslint.config.mjs ================================================ import eslint from "@eslint/js" import tseslint from "@typescript-eslint/eslint-plugin" import tsparser from "@typescript-eslint/parser" import globals from "globals" export default [ { // ignore generated and dependency folders ignores: ["node_modules/**", "out/**"], }, eslint.configs.recommended, { files: ["**/*.ts"], languageOptions: { parser: tsparser, parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname, }, globals: { ...globals.node, }, }, plugins: { "@typescript-eslint": tseslint, }, rules: { ...tseslint.configs.recommended.rules, ...tseslint.configs["recommended-type-checked"].rules, // Custom rules from old config "prefer-const": "error", "no-array-constructor": "error", "no-new-object": "error", "no-shadow": "error", "no-undef-init": "error", "no-var": "error", "object-shorthand": "error", "prefer-template": "error", // Stylistic rules "array-bracket-spacing": "error", "brace-style": "error", "block-spacing": "error", camelcase: "error", "comma-spacing": "error", "eol-last": "error", "func-call-spacing": "error", quotes: ["error", "double"], semi: ["error", "never"], "no-extra-semi": "error", }, }, ] ================================================ FILE: language-configuration.json ================================================ { "comments": { "lineComment": "//", "blockComment": ["/*", "*/"] }, "folding": { "markers": { "start": "^\\s*//\\s*#?region\\b", "end": "^\\s*//\\s*#?endregion\\b" } }, "brackets": [ ["{", "}"], ["[", "]"], ["(", ")"] ], "autoClosingPairs": [ ["{", "}"], ["[", "]"], ["(", ")"], ["\"", "\""], ["'", "'"] ], "surroundingPairs": [ ["{", "}"], ["[", "]"], ["(", ")"], ["\"", "\""], ["'", "'"] ] } ================================================ FILE: package.json ================================================ { "name": "vscode-vlang", "displayName": "V", "description": "V language support (syntax highlighting, formatter, snippets) for Visual Studio Code.", "publisher": "vlanguage", "icon": "icons/icon.png", "version": "0.2.0", "license": "MIT", "engines": { "vscode": "^1.105.0" }, "extensionPack": [ "ms-vscode.cpptools" ], "homepage": "https://vlang.io/", "bugs": { "url": "https://github.com/vlang/vscode-vlang/issues" }, "repository": { "type": "git", "url": "https://github.com/vlang/vscode-vlang" }, "scripts": { "build:base": "esbuild src/extension.ts --bundle --external:vscode --outdir=out --platform=node --target=node24 --format=cjs", "build": "npm run build:base -- --sourcemap", "build:prod": "npm run build:base -- --minify", "watch": "npm run build:base -- --sourcemap --watch", "typecheck": "tsc --noEmit", "lint": "eslint src --ext ts", "lint:md": "markdownlint README.md", "fmt": "prettier -w .", "test": "npm run typecheck && npm run lint", "vscode:prepublish": "npm run build:prod", "package": "npm run build:prod && vsce package", "test:grammar": "vscode-tmgrammar-test source.v -g syntaxes/v.tmLanguage.json syntaxes/tests/*.v" }, "keywords": [ "V", "v", "v language", "vlang", "extension", "autocompletion" ], "categories": [ "Snippets", "Programming Languages" ], "contributes": { "snippets": [ { "language": "v", "path": "snippets/snippets.json" } ], "languages": [ { "id": "v", "aliases": [ "V", "v" ], "extensions": [ ".v", ".vsh" ], "configuration": "language-configuration.json" }, { "id": "v.mod", "aliases": [ "v.mod" ], "extensions": [ "v.mod" ], "configuration": "language-configuration.json" } ], "grammars": [ { "language": "v", "scopeName": "source.v", "path": "syntaxes/v.tmLanguage.json" }, { "language": "v.mod", "scopeName": "v.mod", "path": "syntaxes/v.mod.tmLanguage.json" } ], "configuration": { "type": "object", "title": "V", "properties": { "v.vls.command": { "type": "string", "default": "v", "description": "Path to the V language server binary." }, "v.vls.args": { "type": "array", "default": [], "description": "Arguments to pass to the V language server." }, "v.executablePath": { "scope": "resource", "type": "string", "default": "v", "description": "Custom path to the V compiler executable (`v`).\nNOTE: Setting this won't change the VROOT path in VLS." }, "v.vls.debug": { "scope": "resource", "type": "boolean", "description": "Enables / disables the language server's debug mode.\nSetting it to true will create a log file to your workspace folder for bug reports." }, "v.vls.customVrootPath": { "scope": "resource", "type": "string", "default": "", "description": "Custom path to the V installation directory (VROOT).\nNOTE: Setting this won't change the V compiler executable to be used." }, "v.vls.customPath": { "scope": "resource", "type": "string", "default": "", "description": "Custom path to the VLS (V Language Server) executable." }, "v.vls.enable": { "scope": "resource", "type": "boolean", "default": false, "description": "Enables the language server. (alpha)" }, "v.vls.build": { "scope": "resource", "type": "boolean", "default": true, "description": "Automatically build VLS if it's not found. (Requires V to be installed)" }, "v.vls.forceCleanInstall": { "scope": "resource", "type": "boolean", "default": false, "description": "Removes any existing VLS binary and forces a clean install on startup or vls enabled." }, "v.vls.buildPath": { "scope": "resource", "type": "string", "description": "Path to vls source to build." }, "v.vls.enableFeatures": { "scope": "resource", "type": "string", "description": "Enables specific language server features. Multiple values must be separated with a comma (,)." }, "v.vls.disableFeatures": { "scope": "resource", "type": "string", "description": "Disables specific language server features. Multiple values must be separated with a comma (,)." }, "v.vls.connectionMode": { "scope": "resource", "type": "string", "default": "stdio", "enum": [ "stdio", "tcp" ], "description": "Specify the mode to be used when connecting to VLS. (Only stdio is working currently)", "enumDescriptions": [ "Connects to the language server via standard input/output. (Default)", "Connects to the language server via TCP" ] }, "v.vls.tcpMode.port": { "scope": "resource", "type": "number", "default": 5007, "description": "Port to be used when connecting to the language server. (Only in TCP mode)" }, "v.vls.tcpMode.useRemoteServer": { "scope": "resource", "default": false, "type": "boolean", "description": "Connect to a remote server instead of launching a new local process. (Only in TCP mode)" }, "v.vls.customArgs": { "scope": "resource", "type": "string", "description": "Custom arguments to be passed to the VLS executable." } } }, "configurationDefaults": { "[v]": { "editor.insertSpaces": false } }, "keybindings": [ { "command": "v.fmt", "key": "ctrl+shift+i" } ], "commands": [ { "command": "v.run", "title": "Run current file", "category": "V" }, { "command": "v.fmt", "title": "Format current file", "category": "V" }, { "command": "v.prod", "title": "Build an optimized executable from current file", "category": "V" }, { "command": "v.ver", "title": "Show V version", "category": "V" }, { "command": "v.vls.update", "title": "Update VLS", "category": "V" }, { "command": "v.vls.restart", "title": "Restart VLS", "category": "V" } ], "menus": { "commandPalette": [ { "command": "v.run", "when": "editorLangId == v" }, { "command": "v.fmt", "when": "editorLangId == v" }, { "command": "v.prod", "when": "editorLangId == v" }, { "command": "v.vls.restart", "when": "editorLangId == v && config.v.vls.enable" } ] }, "breakpoints": [ { "language": "v" } ] }, "activationEvents": [ "workspaceContains:**/*.v" ], "main": "./out/extension.js", "dependencies": { "vscode-languageclient": "10.0.0-next.15" }, "devDependencies": { "esbuild": "^0.25.10", "@types/node": "24", "@types/vscode": "1.105.0", "@typescript-eslint/eslint-plugin": "^8.46", "@typescript-eslint/parser": "^8.46", "@vscode/vsce": "^3.6.2", "eslint": "^9.37.0", "globals": "^15.9.0", "markdownlint-cli": "^0.45.0", "prettier": "^3.6.2", "typescript": "^5.9.3", "vscode-tmgrammar-test": "~0.1.3" } } ================================================ FILE: snippets/snippets.json ================================================ { "snippet.assert": { "body": ["assert ${1:expression}"], "description": "Code snippet for testing 'assert'", "prefix": "as", "scope": "v,vlang" }, "snippet.unimpl": { "body": ["assert false, 'unimplemented'"], "description": "Code snippet for unimplemented 'assert'", "prefix": "unimpl", "scope": "v,vlang" }, "snippet.unreach": { "body": ["assert false, 'unreachable'"], "description": "Code snippet for unreachable 'assert'", "prefix": "unreach", "scope": "v,vlang" }, "snippet.break": { "body": ["break$0"], "description": "Code snippet for 'break'", "prefix": "br", "scope": "v,vlang" }, "snippet.const": { "body": ["const ${1:name} = ${2:value}"], "description": "Code snippet for 'const'", "prefix": "co", "scope": "v,vlang" }, "snippet.const.multiply": { "body": ["const (", "\t$0", ")"], "description": "Code snippet for multiply 'const'", "prefix": "cons", "scope": "v,vlang" }, "snippet.continue": { "body": ["continue$0"], "description": "Code snippet for 'continue'", "prefix": "con", "scope": "v,vlang" }, "snippet.defer": { "body": ["defer {", "\t$0", "}"], "description": "Code snippet for 'defer' block", "prefix": "def", "scope": "v,vlang" }, "snippet.else": { "body": ["else {", "\t$0", "}"], "description": "Code snippet for 'else' statement", "prefix": "el", "scope": "v,vlang" }, "snippet.elseif": { "body": ["else if ${1:expression} {", "\t$0", "}"], "description": "Code snippet for 'else if' statement", "prefix": "elf", "scope": "v,vlang" }, "snippet.enum": { "body": ["enum ${1:name} {", "\t$0", "}"], "description": "Code snippet for 'enum'", "prefix": "en", "scope": "v,vlang" }, "snippet.flag": { "body": ["#flag ${1:-flag}"], "description": "Code snippet for '#flag'", "prefix": "fl", "scope": "v,vlang" }, "snippet.fn.eprint": { "body": ["eprint('${1:text}')"], "description": "Code snippet for standart based function 'eprint'", "prefix": "epr", "scope": "v,vlang" }, "snippet.fn.eprintln": { "body": ["eprintln('${1:text}')"], "description": "Code snippet for standart based function 'eprintln'", "prefix": "eprl", "scope": "v,vlang" }, "snippet.fn.init": { "body": ["fn init() {", "\t$0", "}"], "description": "Code snippet for 'init' function", "prefix": "finit", "scope": "v,vlang" }, "snippet.fn.main": { "body": ["fn main() {", "\t$0", "}"], "description": "Code snippet for 'main' function", "prefix": "fmain", "scope": "v,vlang" }, "snippet.fn.print": { "body": ["print('${1:text}')"], "description": "Code snippet for standart based function 'print'", "prefix": "pr", "scope": "v,vlang" }, "snippet.fn.println": { "body": ["println('${1:text}')"], "description": "Code snippet for standart based function 'println'", "prefix": "prl", "scope": "v,vlang" }, "snippet.for": { "body": ["for {", "\t$0", "}"], "description": "Code snippet for pure infinity loop 'for'", "prefix": "for", "scope": "v,vlang" }, "snippet.for.index": { "body": ["for ${1:i} := 0; $1 < ${3:count}; $1++ {", "\t$0", "}"], "description": "Code snippet for index loop 'for'", "prefix": "for", "scope": "v,vlang" }, "snippet.foreach": { "body": ["for ${1:variable} in ${2:array} {", "\t$0", "}"], "description": "Code snippet for foreach 'for'", "prefix": "fore", "scope": "v,vlang" }, "snippet.foreach.index": { "body": ["for ${1:_}, ${2:variable} in ${3:array} {", "\t$0", "}"], "description": "Code snippet for index based loop 'for'", "prefix": "fore", "scope": "v,vlang" }, "snippet.function": { "body": ["fn ${1:name}() {", "\t$0", "}"], "description": "Code snippet for function 'fn'", "prefix": "fn", "scope": "v,vlang" }, "snippet.go": { "body": ["go ${1:function}($0)"], "description": "Code snippet for concurrency 'go'", "prefix": "go", "scope": "v,vlang" }, "snippet.goto": { "body": ["goto ${1:label}"], "description": "Code snippet for 'goto' label", "prefix": "got", "scope": "v,vlang" }, "snippet.if": { "body": ["if ${1:expression} {", "\t$0", "}"], "description": "Code snippet for 'if' statement", "prefix": "if", "scope": "v,vlang" }, "snippet.if.compile": { "body": ["\\$if ${1:expression} {", "\t$0", "}"], "description": "Code snippet for compile time 'if'", "prefix": "$i", "scope": "v,vlang" }, "snippet.ifelse": { "body": ["if ${1:expression} {", "\t$0", "} else {", "\t$0", "}"], "description": "Code snippet for 'if-else' statement", "prefix": "ie", "scope": "v,vlang" }, "snippet.import": { "body": ["import ${1:module}"], "description": "Code snippet for 'import' module", "prefix": "imp", "scope": "v,vlang" }, "snippet.include": { "body": ["#include <${1:name}>"], "description": "Code snippet for C '#include'", "prefix": "inc", "scope": "v,vlang" }, "snippet.interface": { "body": ["interface ${1:name} {$0}"], "description": "Code snippet for 'interface'", "prefix": "inte", "scope": "v,vlang" }, "snippet.map": { "body": ["map[${1:key}]${2:value}{$0}"], "description": "Code snippet for 'map'", "prefix": "map", "scope": "v,vlang" }, "snippet.match": { "body": ["match ${1:expression} {", "\t$0", "}"], "description": "Code snippet for 'match' statement", "prefix": "ma", "scope": "v,vlang" }, "snippet.module": { "body": ["module ${1:name}"], "description": "Code snippet for 'module'", "prefix": "mod", "scope": "v,vlang" }, "snippet.public.function": { "body": ["pub fn ${1:name}() {", "\t$0", "}"], "description": "Code snippet for public function 'pub fn'", "prefix": "pub", "scope": "v,vlang" }, "snippet.return": { "body": ["return ${1:value}"], "description": "Code snippet for 'return'", "prefix": "ret", "scope": "v,vlang" }, "snippet.struct": { "body": ["struct ${1:Name} {", "\t$0", "}"], "description": "Code snippet for 'struct'", "prefix": "stru", "scope": "v,vlang" }, "snippet.type": { "body": ["type ${1:name} = ${2:type}"], "description": "Code snippet for 'type' definition", "prefix": "ty", "scope": "v,vlang" }, "snippet.type.bool": { "body": ["bool"], "description": "Code snippet for Boolean", "prefix": "bool", "scope": "v,vlang" }, "snippet.type.byte": { "body": ["byte"], "description": "Code snippet for Unsigned 8-bit Integer", "prefix": "byte", "scope": "v,vlang" }, "snippet.type.byteptr": { "body": ["byteptr"], "description": "Code snippet for Byte*", "prefix": "bptr", "scope": "v,vlang" }, "snippet.type.f32": { "body": ["f32"], "description": "Code snippet for 32-bit FloatingPoint", "prefix": "float", "scope": "v,vlang" }, "snippet.type.f64": { "body": ["f64"], "description": "Code snippet for 64-bit FloatingPoint", "prefix": "float64", "scope": "v,vlang" }, "snippet.type.i8": { "body": ["i8"], "description": "Code snippet for Signed 8-bit Integer", "prefix": "int8", "scope": "v,vlang" }, "snippet.type.i16": { "body": ["i16"], "description": "Code snippet for Signed 16-bit Integer", "prefix": "int16", "scope": "v,vlang" }, "snippet.type.i64": { "body": ["i64"], "description": "Code snippet for Signed 64-bit Integer", "prefix": "int64", "scope": "v,vlang" }, "snippet.type.int": { "body": ["int"], "description": "Code snippet for Signed 32-bit Integer", "prefix": "int", "scope": "v,vlang" }, "snippet.type.rune": { "body": ["rune"], "description": "Code snippet for Represents a Unicode CodePoint", "prefix": "rune", "scope": "v,vlang" }, "snippet.type.string": { "body": ["string"], "description": "Code snippet for String", "prefix": "str", "scope": "v,vlang" }, "snippet.type.u16": { "body": ["u16"], "description": "Code snippet for Unsigned 16-bit Integer", "prefix": "u16", "scope": "v,vlang" }, "snippet.type.u32": { "body": ["u32"], "description": "Code snippet for Unsigned 32-bit Integer", "prefix": "u32", "scope": "v,vlang" }, "snippet.type.u64": { "body": ["u64"], "description": "Code snippet for Unsigned 64-bit Integer", "prefix": "u64", "scope": "v,vlang" }, "snippet.type.voidptr": { "body": ["voidptr"], "description": "Code snippet for void*", "prefix": "vptr", "scope": "v,vlang" }, "snippet.type.charptr": { "body": ["charptr"], "description": "Code snippet for char*", "prefix": "cptr", "scope": "v,vlang" } } ================================================ FILE: src/commands.ts ================================================ import { vlsOutputChannel } from "logger" import { commands, ExtensionContext, window } from "vscode" import type { LanguageClient } from "vscode-languageclient/node" import { execVInTerminal, execVInTerminalOnBG } from "./exec" /** Run the currently active V file using `v run`. */ export async function run(): Promise { const document = window.activeTextEditor?.document if (!document) { void window.showErrorMessage("No active V file to run.") return } await document.save() const filePath = `"${document.fileName}"` execVInTerminal(["run", filePath]) } /** Format the currently active V file in-place using `v fmt -w`. */ export async function fmt(): Promise { const document = window.activeTextEditor?.document if (!document) { void window.showErrorMessage("No active V file to format.") return } await document.save() const filePath = `"${document.fileName}"` await execVInTerminalOnBG(["fmt", "-w", filePath]) } /** Build an optimized executable from the current file using `v -prod`. */ export async function prod(): Promise { const document = window.activeTextEditor?.document if (!document) { void window.showErrorMessage("No active V file to build.") return } await document.save() const filePath = `"${document.fileName}"` execVInTerminal(["-prod", filePath]) } /** Show version information of the configured `v` executable. */ export function ver(): void { execVInTerminalOnBG(["-version"]).catch((err) => { void window.showErrorMessage(`Failed to get V version: ${err}. Is V installed correctly?`) }) } export async function updateVls(client?: LanguageClient): Promise { // For now, show an informational message. If we had an update mechanism // (download/install), it would be invoked here and possibly restart the client. void window.showInformationMessage("Update VLS: not implemented.") // If a client is provided, optionally restart to pick up a new binary. if (client) { try { await client.stop() await client.start() void window.showInformationMessage("VLS has been restarted after update.") } catch { // ignore error details for now void window.showErrorMessage("Failed to restart VLS after update.") } } } export async function restartVls(cli?: LanguageClient): Promise { if (!cli) { void window.showErrorMessage("VLS client is not running.") return } try { await cli.restart() void window.showInformationMessage("VLS restarted successfully.") } catch { void window.showErrorMessage("Failed to restart VLS.") } } export function registerCommands(context: ExtensionContext): Promise { context.subscriptions.push( commands.registerCommand("v.run", run), commands.registerCommand("v.fmt", fmt), commands.registerCommand("v.ver", ver), commands.registerCommand("v.prod", prod), ) return Promise.resolve() } export function registerVlsCommands(context: ExtensionContext, client?: LanguageClient): void { context.subscriptions.push( commands.registerCommand("v.vls.update", () => updateVls(client)), commands.registerCommand("v.vls.restart", () => restartVls(client)), commands.registerCommand("v.vls.openOutput", () => { vlsOutputChannel.show() }), ) } ================================================ FILE: src/exec.ts ================================================ import { exec as _exec } from "child_process" import { promisify } from "util" import { Terminal, window } from "vscode" import { config } from "./utils" let vRunTerm: Terminal | null = null const exec = promisify(_exec) // Get V executable command. export function getVExecCommand(): string { return config().get("executablePath") //default is v } export function execVInTerminal(args: string[]): void { const vexec = getVExecCommand() const cmd = `${vexec} ${args.join(" ")}` if (!vRunTerm) vRunTerm = window.createTerminal("V") vRunTerm.show() vRunTerm.sendText(cmd) } export async function execVInTerminalOnBG(args: string[], cwd = "/"): Promise { const vexec = getVExecCommand() const cmd = `${vexec} ${args.join(" ")}` await exec(cmd, { cwd }) } ================================================ FILE: src/extension.ts ================================================ import { registerCommands, registerVlsCommands } from "commands" import { getVls, isVlsEnabled } from "langserver" import { log, outputChannel, vlsOutputChannel } from "logger" import vscode, { ConfigurationChangeEvent, ExtensionContext, workspace } from "vscode" import { LanguageClient, LanguageClientOptions, ServerOptions } from "vscode-languageclient/node" import { installV, isVInstalled } from "./utils" export let client: LanguageClient | undefined async function createAndStartClient(): Promise { const vlsPath = await getVls() const serverOptions: ServerOptions = { run: { command: vlsPath }, debug: { command: vlsPath }, } const clientOptions: LanguageClientOptions = { documentSelector: [{ scheme: "file", language: "v" }], outputChannel: vlsOutputChannel, synchronize: { fileEvents: vscode.workspace.createFileSystemWatcher("**/*.v"), }, } client = new LanguageClient("vls", "V Language Server", serverOptions, clientOptions) vscode.window.showInformationMessage("V Language Server is starting.") await client.start() vscode.window.showInformationMessage("V Language Server is now active.") } export async function activate(context: ExtensionContext): Promise { // Register output channels so users can open them even without VLS. context.subscriptions.push(outputChannel, vlsOutputChannel) // Check for V only if it's not installed if (!(await isVInstalled())) { const selection = await vscode.window.showInformationMessage( "The V programming language is not detected on this system. Would you like to install it?", { modal: true }, // Modal makes the user have to choose before continuing "Yes", "No", ) if (selection === "Yes") { await installV() } } // Register commands regardless of whether VLS is enabled await registerCommands(context) // Only start the language server if the user enabled it in settings. if (isVlsEnabled()) { try { await createAndStartClient() } catch (err) { // If starting the client fails, log and continue. Users can still // use non-LSP features of the extension. console.error("Failed to start VLS:", err) vscode.window.showErrorMessage("Failed to start VLS. See output for details.") outputChannel.show() } } else { log("VLS is disabled in settings.") } registerVlsCommands(context, client) // React to configuration changes: enable/disable or request restart. workspace.onDidChangeConfiguration(async (e: ConfigurationChangeEvent) => { const vlsEnabled = isVlsEnabled() if (e.affectsConfiguration("v.vls.enable")) { if (vlsEnabled && !client) { // Start the client now that the user enabled it. try { await createAndStartClient() } catch (err) { console.error("Failed to start VLS:", err) vscode.window.showErrorMessage("Failed to start VLS. See output for details.") outputChannel.show() } } else if (!vlsEnabled && client) { // Stop the client if it was running and the user disabled it. try { await client.stop() log("VLS has been stopped.") } catch { // ignore } client = undefined } } else if (e.affectsConfiguration("v.vls") && vlsEnabled && client) { void vscode.window .showInformationMessage( "VLS: Restart is required for changes to take effect. Would you like to proceed?", "Yes", "No", ) .then(async (selected) => { if (selected == "Yes") { try { if (client) { await client.restart() } } catch { void vscode.window.showErrorMessage("Failed to restart VLS.") } } }) } }) } export function deactivate(): Promise | undefined { if (!client) return undefined return client.stop() } ================================================ FILE: src/langserver.ts ================================================ import * as os from "os" import * as path from "path" import { window } from "vscode" import { log } from "./logger" import { vlsConfig } from "./utils" import { exec as _exec } from "child_process" import { promises as fs } from "fs" import { promisify } from "util" import { execVInTerminalOnBG } from "./exec" import { isVInstalled } from "./utils" const exec = promisify(_exec) export const BINARY_NAME = process.platform === "win32" ? "vls.exe" : "vls" export const USER_BIN_PATH = path.join(os.homedir(), ".local", "bin") export const VLS_PATH = path.join(USER_BIN_PATH, BINARY_NAME) // ~/.local/bin/vls if not tmp enabled export async function getVls(): Promise { if (vlsConfig().get("forceCleanInstall")) { await fs.rm(VLS_PATH, { recursive: true, force: true }) log("forceCleanInstall is enabled, removed existing VLS.") } else if (await isVlsInstalled()) { // dont check if installed if forceCleanInstall is true return VLS_PATH } const selected = await window.showInformationMessage( "VLS is not installed. Do you want to install it now?", "Yes", "No", ) if (selected === "No") { throw new Error("VLS is required but not installed.") } if (!vlsConfig().get("build")) { return await installVls() } return await buildVls() } export function isVlsEnabled(): boolean { return vlsConfig().get("enable") } export async function isVlsInstalled(): Promise { try { // Check if file exists await fs.access(VLS_PATH) log(`Using existing VLS at ${VLS_PATH}`) return true } catch { // File doesn't exist — ignore and proceed to build/install return false } } export function installVls(): Promise { // TODO: Install latest vls from github once there are releases return Promise.reject( new Error("VLS builds not yet available. Please enable vls.build in settings."), ) } export async function buildVls(): Promise { if (!(await isVInstalled())) { throw new Error("V must be installed to build VLS.") } let buildPath try { log("Building VLS...") window.showInformationMessage("Building VLS...") if (vlsConfig().get("buildPath") !== "") { buildPath = vlsConfig().get("buildPath") } else { // Use temporary directory for cross-platform compatibility buildPath = path.join(os.tmpdir(), "vls") // Remove any existing directory at buildPath await fs.rm(buildPath, { recursive: true, force: true }) // Clone the repo into buildPath await exec(`git clone --depth 1 https://github.com/vlang/vls.git ${buildPath}`) } await execVInTerminalOnBG(["."], buildPath) // build // Ensure target dir exists await fs.mkdir(path.dirname(VLS_PATH), { recursive: true }) // Copy binary using Node fs to support Windows await fs.copyFile(path.join(buildPath, BINARY_NAME), VLS_PATH) log(`VLS built and installed at ${VLS_PATH}`) return VLS_PATH } catch (err) { const message = err instanceof Error ? err.message : String(err) log(`Failed to build or install VLS: ${message}`) throw new Error(`Failed to build or install VLS: ${message}`) } } ================================================ FILE: src/logger.ts ================================================ import { window } from "vscode" export const outputChannel = window.createOutputChannel("V", { log: true }) export const vlsOutputChannel = window.createOutputChannel("V Language Server", { log: true }) export function log(msg: string): void { // logging for devtools/debug console.log(`[vscode-vlang] ${msg}`) outputChannel.info(msg) } ================================================ FILE: src/utils.ts ================================================ import { exec as _exec } from "child_process" import { getVExecCommand } from "exec" import * as fs from "fs" import { USER_BIN_PATH } from "langserver" import { log } from "logger" import * as os from "os" import * as path from "path" import { promisify } from "util" import { ProgressLocation, Uri, window, workspace, WorkspaceFolder } from "vscode" export const config = () => workspace.getConfiguration("v") export const vlsConfig = () => workspace.getConfiguration("v.vls") const exec = promisify(_exec) /** Get current working directory. * @param uri The URI of document */ export function getCwd(uri?: Uri): string { const folder = getWorkspaceFolder(uri || null) return folder.uri.fsPath } /** Get workspace of current document. * @param uri The URI of document */ export function getWorkspaceFolder(uri?: Uri): WorkspaceFolder { if (uri) { return workspace.getWorkspaceFolder(uri) } else if (window.activeTextEditor && window.activeTextEditor.document) { return workspace.getWorkspaceFolder(window.activeTextEditor.document.uri) } else { return workspace.workspaceFolders[0] } } /** * Checks if the 'v' command is available in the system's PATH. * @returns A promise that resolves to true if 'v' is installed, otherwise false. */ export async function isVInstalled(): Promise { const vexec = getVExecCommand() try { // A simple command to check if V is installed and in the PATH. const version = await exec(`${vexec} --version`) log(`V is already installed, version: ${version.stdout.trim()}`) return true } catch (error) { log(`V is not detected in PATH: ${error}`) return false } } /** * Clone and build the `v` compiler * * Returns: absolute path to the `v` binary (string) * Error: rejects if any git/make step fails */ export async function installV(): Promise { const installDir = USER_BIN_PATH const vRepoPath = path.join(installDir, "v") const repoUrl = "https://github.com/vlang/v" await window.withProgress( { location: ProgressLocation.Notification, title: "Installing V Language", cancellable: false, }, async (progress) => { try { // 0. Clean up any previous failed attempts progress.report({ message: "Preparing workspace..." }) if (fs.existsSync(installDir)) { fs.rmSync(installDir, { recursive: true, force: true }) } fs.mkdirSync(installDir) // 1. Clone the repository progress.report({ message: "Cloning V repository..." }) await exec(`git clone --depth=1 ${repoUrl}`, { cwd: installDir }) // 2. Build V using make progress.report({ message: "Building V from source (this may take a moment)..." }) await exec("make", { cwd: vRepoPath }) // 3. Create a symlink // This command often requires sudo/admin privileges. // We run it and inform the user to run it manually if it fails. progress.report({ message: "Attempting to create symlink..." }) try { // On Windows, the build script handles the path. On Linux/macOS, symlink is used. const symlinkCommand = os.platform() === "win32" ? "v.exe symlink" : "./v symlink" await exec(symlinkCommand, { cwd: vRepoPath }) window.showInformationMessage( "V language installed and linked successfully! Please restart VS Code to use the `v` command.", ) } catch (symlinkError) { console.error(symlinkError) window.showWarningMessage( `V was built successfully, but the automatic symlink failed (likely due to permissions). Please run '${path.join(vRepoPath, "v")} symlink' manually with administrator/sudo rights.`, "OK", ) } } catch (error) { console.error(error) window.showErrorMessage( `Failed to install V. Please check the logs for details. Error: ${error}`, ) } }, ) } ================================================ FILE: syntaxes/tests/accessor.v ================================================ // SYNTAX TEST "source.v" "method accessor" hello.world // ^ punctuation.accessor.v ================================================ FILE: syntaxes/tests/comma.v ================================================ // SYNTAX TEST "source.v" "comma" [1, 2, 3, 4] // ^ punctuation.separator.comma.v // ^ punctuation.separator.comma.v // ^ punctuation.separator.comma.v ================================================ FILE: syntaxes/tests/comparison.v ================================================ // SYNTAX TEST "source.v" "comparison" 0 == 0 // ^ constant.numeric.integer.v // ^^ keyword.operator.relation.v // ^ constant.numeric.integer.v ================================================ FILE: syntaxes/tests/dot.int.v ================================================ // SYNTAX TEST "source.v" hello.int() // ^^^ entity.name.function.v ================================================ FILE: syntaxes/tests/escape.v ================================================ // SYNTAX TEST "source.v" @type // ^^^^^ source.v - keyword.type.v ================================================ FILE: syntaxes/tests/function.v ================================================ // SYNTAX TEST "source.v" pub fn foo() // ^^^ storage.modifier.v // ^^ keyword.fn.v // ^^^ entity.name.function.v // ^ entity.name.generic.v fn foo() // ^^ keyword.fn.v // ^^^ entity.name.function.v pub fn foo() // ^^^ storage.modifier.v // ^^ keyword.fn.v // ^^^ entity.name.function.v pub fn (test Blah) foo() // ^^^ storage.modifier.v // ^^ keyword.fn.v // ^^^ entity.name.function.v fn C.foo() // ^^ keyword.fn.v // ^^^ entity.name.function.v ================================================ FILE: syntaxes/tests/hashtag.v ================================================ // SYNTAX TEST "source.v" "hashtag" #include // ^^^^^^^^^^^^^^^ markup.bold.v #define foo bar // ^^^^^^^^^^^^ markup.bold.v #some javascript line // ^^^^^^^^^^^^^^^^^^ markup.bold.v ================================================ FILE: syntaxes/tests/method.v ================================================ // SYNTAX TEST "source.v" "method accessor" hello.method() // ^^^^^^ entity.name.function.v ================================================ FILE: syntaxes/tests/numbers.v ================================================ // SYNTAX TEST "source.v" "numbers" _ := 1_000_000 // ^^^^^^^^^ constant.numeric.integer.v _ := 3_122.55 // ^^^^^^^^ constant.numeric.float.v _ := 3.14e11 // ^^^^^^^ constant.numeric.exponential.v _ := 0xF_F // ^^^^^ constant.numeric.hex.v _ := 0o17_3 // ^^^^^^ constant.numeric.octal.v _ := 0b0_11 // ^^^^^^ constant.numeric.binary.v ================================================ FILE: syntaxes/tests/optional.v ================================================ // SYNTAX TEST "source.v" "optional" fn f(url string) ?string { // ^ keyword.operator.optional.v ================================================ FILE: syntaxes/tests/pubfn.v ================================================ // SYNTAX TEST "source.v" pubfn // ^^^ - storage.modifier.v // ^^ - keyword.fn.v pub fn // ^^^ storage.modifier.v // ^^ keyword.fn.v pub fn // test // ^^ comment.line.double-slash.v ================================================ FILE: syntaxes/tests/string.v ================================================ // SYNTAX TEST "source.v" "string" _ := 'test' // ^^^^ string.quoted.v a := 1 b := 2 _ := '$a' // ^^ string.quoted.v _ := '\\' // ^^ constant.character.escape.v _ := c'test' // ^ storage.type.string.v _ := `r` // ^^^ string.quoted.rune.v _ := r'\' // ^ storage.type.string.v // ^^^ string.quoted.raw.v _ := r"\" // ^ storage.type.string.v // ^^^ string.quoted.raw.v _ := r'$a' // ^ storage.type.string.v // ^^^ string.quoted.raw.v _ := '${a + b}' // ^^ punctuation.definition.template-expression.begin.v // ^ keyword.operator.arithmetic.v // ^ variable.other.v // ^ punctuation.definition.template-expression.end.v ================================================ FILE: syntaxes/tests/type.v ================================================ // SYNTAX TEST "source.v" struct Foo {} // ^^^ entity.name.type.v type Foo = int // ^^^ entity.name.type.v ================================================ FILE: syntaxes/tests/variable.v ================================================ // SYNTAX TEST "source.v" abc := '' // ^^^ variable.other.assignment.v mut abc := '' // ^^^ variable.other.assignment.v abc = '' // ^^^ variable.other.assignment.v abc, foo := '', '' // ^^^ variable.other.assignment.v // ^^ - variable.other.assignment.v // ^^^ variable.other.assignment.v variable2 := 2 // ^^^^^^^^^ variable.other.assignment.v // ^ - constant.numeric.integer.v ================================================ FILE: syntaxes/v.mod.tmLanguage.json ================================================ { "scopeName": "v.mod", "patterns": [ { "include": "#module-decl" }, { "include": "#brackets" }, { "include": "#field" }, { "include": "#string-placeholder" } ], "repository": { "module-decl": { "name": "keyword.module.v.mod", "match": "(\\bModule)" }, "brackets": { "patterns": [ { "begin": "{", "beginCaptures": { "0": { "name": "punctuation.definition.bracket.curly.begin.v.mod" } }, "end": "}", "endCaptures": { "0": { "name": "punctuation.definition.bracket.curly.end.v.mod" } } } ] }, "field": { "name": "meta.definition.field.$1.v.mod", "match": "\\b'([\\w]+)':\\s*'([\\w]*)'\\s*" }, "string": { "name": "meta.definition.string.v.mod", "begin": "'", "beginCaptures": { "0": { "name": "storage.type.string.v.mod" } }, "end": "'", "endCaptures": { "0": { "name": "storage.type.string.v.mod" } }, "patterns": [ { "include": "#string-placeholder" } ] }, "string-placeholder": { "match": "%(\\[\\d+\\])?([\\+#\\-0\\x20]{,2}((\\d+|\\*)?(\\.?(\\d+|\\*|(\\[\\d+\\])\\*?)?(\\[\\d+\\])?)?))?[vT%tbcdoqxXUbeEfFgGsp]", "name": "constant.other.placeholder.v.mod" } } } ================================================ FILE: syntaxes/v.tmLanguage.json ================================================ { "name": "V", "scopeName": "source.v", "fileTypes": [".v", ".vh", ".vsh"], "patterns": [ { "include": "#comments" }, { "include": "#function-decl" }, { "include": "#as-is" }, { "include": "#attributes" }, { "include": "#assignment" }, { "include": "#module-decl" }, { "include": "#import-decl" }, { "include": "#hash-decl" }, { "include": "#brackets" }, { "include": "#builtin-fix" }, { "include": "#escaped-fix" }, { "include": "#operators" }, { "include": "#function-limited-overload-decl" }, { "include": "#function-extend-decl" }, { "include": "#function-exist" }, { "include": "#generic" }, { "include": "#constants" }, { "include": "#type" }, { "include": "#enum" }, { "include": "#interface" }, { "include": "#struct" }, { "include": "#keywords" }, { "include": "#storage" }, { "include": "#numbers" }, { "include": "#strings" }, { "include": "#types" }, { "include": "#punctuations" }, { "include": "#variable-assign" }, { "include": "#function-decl" } ], "repository": { "as-is": { "begin": "\\s+(as|is)\\s+", "beginCaptures": { "1": { "name": "keyword.$1.v" } }, "end": "([\\w.]*)", "endCaptures": { "1": { "name": "entity.name.alias.v" } } }, "assignment": { "name": "meta.definition.variable.v", "match": "\\s+((?:\\:|\\+|\\-|\\*|/|\\%|\\&|\\||\\^)?=)\\s+", "captures": { "1": { "patterns": [ { "include": "#operators" } ] } } }, "attributes": { "name": "meta.definition.attribute.v", "match": "^\\s*((\\[)(deprecated|unsafe|console|heap|manualfree|typedef|live|inline|flag|ref_only|direct_array_access|callconv)(\\]))", "captures": { "1": { "name": "meta.function.attribute.v" }, "2": { "name": "punctuation.definition.begin.bracket.square.v" }, "3": { "name": "storage.modifier.attribute.v" }, "4": { "name": "punctuation.definition.end.bracket.square.v" } } }, "variable-assign": { "match": "[a-zA-Z_]\\w*(?:,\\s*[a-zA-Z_]\\w*)*(?=\\s*(?:=|:=))", "captures": { "0": { "patterns": [ { "match": "[a-zA-Z_]\\w*", "name": "variable.other.assignment.v" }, { "include": "#punctuation" } ] } } }, "module-decl": { "name": "meta.module.v", "begin": "^\\s*(module)\\s+", "beginCaptures": { "1": { "name": "keyword.module.v" } }, "end": "([\\w.]+)", "endCaptures": { "1": { "name": "entity.name.module.v" } } }, "import-decl": { "name": "meta.import.v", "begin": "^\\s*(import)\\s+", "beginCaptures": { "1": { "name": "keyword.import.v" } }, "end": "([\\w.]+)", "endCaptures": { "1": { "name": "entity.name.import.v" } } }, "hash-decl": { "name": "markup.bold.v", "begin": "^\\s*(#)", "end": "$" }, "brackets": { "patterns": [ { "begin": "{", "beginCaptures": { "0": { "name": "punctuation.definition.bracket.curly.begin.v" } }, "end": "}", "endCaptures": { "0": { "name": "punctuation.definition.bracket.curly.end.v" } }, "patterns": [ { "include": "$self" } ] }, { "begin": "\\(", "beginCaptures": { "0": { "name": "punctuation.definition.bracket.round.begin.v" } }, "end": "\\)", "endCaptures": { "0": { "name": "punctuation.definition.bracket.round.end.v" } }, "patterns": [ { "include": "$self" } ] }, { "begin": "\\[", "beginCaptures": { "0": { "name": "punctuation.definition.bracket.square.begin.v" } }, "end": "\\]", "endCaptures": { "0": { "name": "punctuation.definition.bracket.square.end.v" } }, "patterns": [ { "include": "$self" } ] } ] }, "builtin-fix": { "patterns": [ { "patterns": [ { "name": "storage.modifier.v", "match": "(const)(?=\\s*\\()" }, { "name": "keyword.$1.v", "match": "\\b(fn|type|enum|struct|union|interface|map|assert|sizeof|typeof|__offsetof)\\b(?=\\s*\\()" } ] }, { "patterns": [ { "name": "keyword.control.v", "match": "(\\$if|\\$else)(?=\\s*\\()" }, { "name": "keyword.control.v", "match": "\\b(as|in|is|or|break|continue|default|unsafe|match|if|else|for|go|spawn|goto|defer|return|shared|select|rlock|lock|atomic|asm)\\b(?=\\s*\\()" } ] }, { "patterns": [ { "match": "(?)", "captures": { "1": { "name": "punctuation.definition.bracket.angle.begin.v" }, "2": { "patterns": [ { "include": "#illegal-name" }, { "match": "\\w+", "name": "entity.name.generic.v" } ] }, "3": { "name": "punctuation.definition.bracket.angle.end.v" } } } ] }, "function-decl": { "name": "meta.definition.function.v", "match": "^(\\bpub\\b\\s+)?(\\bfn\\b)\\s+(?:\\([^\\)]+\\)\\s+)?(?:(?:C\\.)?)(\\w+)\\s*((?<=[\\w\\s+])(\\<)(\\w+)(\\>))?", "captures": { "1": { "name": "storage.modifier.v" }, "2": { "name": "keyword.fn.v" }, "3": { "name": "entity.name.function.v" }, "4": { "patterns": [ { "include": "#generic" } ] } } }, "function-extend-decl": { "name": "meta.definition.function.v", "match": "^\\s*(pub)?\\s*(fn)\\s*(\\()([^\\)]*)(\\))\\s*(?:(?:C\\.)?)(\\w+)\\s*((?<=[\\w\\s+])(\\<)(\\w+)(\\>))?", "captures": { "1": { "name": "storage.modifier.v" }, "2": { "name": "keyword.fn.v" }, "3": { "name": "punctuation.definition.bracket.round.begin.v" }, "4": { "patterns": [ { "include": "#brackets" }, { "include": "#storage" }, { "include": "#generic" }, { "include": "#types" }, { "include": "#punctuation" } ] }, "5": { "name": "punctuation.definition.bracket.round.end.v" }, "6": { "patterns": [ { "include": "#illegal-name" }, { "match": "\\w+", "name": "entity.name.function.v" } ] }, "7": { "patterns": [ { "include": "#generic" } ] } } }, "function-limited-overload-decl": { "name": "meta.definition.function.v", "match": "^\\s*(pub)?\\s*(fn)\\s*(\\()([^\\)]*)(\\))\\s*([\\+\\-\\*\\/])?\\s*(\\()([^\\)]*)(\\))\\s*(?:(?:C\\.)?)(\\w+)", "captures": { "1": { "name": "storage.modifier.v" }, "2": { "name": "keyword.fn.v" }, "3": { "name": "punctuation.definition.bracket.round.begin.v" }, "4": { "patterns": [ { "include": "#brackets" }, { "include": "#storage" }, { "include": "#generic" }, { "include": "#types" }, { "include": "#punctuation" } ] }, "5": { "name": "punctuation.definition.bracket.round.end.v" }, "6": { "patterns": [ { "include": "#operators" } ] }, "7": { "name": "punctuation.definition.bracket.round.begin.v" }, "8": { "patterns": [ { "include": "#brackets" }, { "include": "#storage" }, { "include": "#generic" }, { "include": "#types" }, { "include": "#punctuation" } ] }, "9": { "name": "punctuation.definition.bracket.round.end.v" }, "10": { "patterns": [ { "include": "#illegal-name" }, { "match": "\\w+", "name": "entity.name.function.v" } ] } } }, "function-exist": { "name": "meta.support.function.v", "match": "(\\w+)((?<=[\\w\\s+])(\\<)(\\w+)(\\>))?(?=\\s*\\()", "captures": { "0": { "name": "meta.function.call.v" }, "1": { "patterns": [ { "include": "#illegal-name" }, { "match": "\\w+", "name": "entity.name.function.v" } ] }, "2": { "patterns": [ { "include": "#generic" } ] } } }, "type": { "name": "meta.definition.type.v", "match": "^\\s*(?:(pub)?\\s+)?(type)\\s+(\\w*)\\s+(?:\\w+\\.+)?(\\w*)", "captures": { "1": { "name": "storage.modifier.$1.v" }, "2": { "name": "storage.type.type.v" }, "3": { "patterns": [ { "include": "#illegal-name" }, { "include": "#types" }, { "name": "entity.name.type.v", "match": "\\w+" } ] }, "4": { "patterns": [ { "include": "#illegal-name" }, { "include": "#types" }, { "name": "entity.name.type.v", "match": "\\w+" } ] } } }, "enum": { "name": "meta.definition.enum.v", "match": "^\\s*(?:(pub)?\\s+)?(enum)\\s+(?:\\w+\\.)?(\\w*)", "captures": { "1": { "name": "storage.modifier.$1.v" }, "2": { "name": "storage.type.enum.v" }, "3": { "name": "entity.name.enum.v" } } }, "interface": { "name": "meta.definition.interface.v", "match": "^\\s*(?:(pub)?\\s+)?(interface)\\s+(\\w*)", "captures": { "1": { "name": "storage.modifier.$1.v" }, "2": { "name": "keyword.interface.v" }, "3": { "patterns": [ { "include": "#illegal-name" }, { "name": "entity.name.interface.v", "match": "\\w+" } ] } } }, "struct": { "patterns": [ { "name": "meta.definition.struct.v", "begin": "^\\s*(?:(mut|pub(?:\\s+mut)?|__global)\\s+)?(struct|union)\\s+([\\w.]+)\\s*|({)", "beginCaptures": { "1": { "name": "storage.modifier.$1.v" }, "2": { "name": "storage.type.struct.v" }, "3": { "name": "entity.name.type.v" }, "4": { "name": "punctuation.definition.bracket.curly.begin.v" } }, "end": "\\s*|(})", "endCaptures": { "1": { "name": "punctuation.definition.bracket.curly.end.v" } }, "patterns": [ { "include": "#struct-access-modifier" }, { "match": "\\b(\\w+)\\s+([\\w\\[\\]\\*&.]+)(?:\\s*(=)\\s*((?:.(?=$|//|/\\*))*+))?", "captures": { "1": { "name": "variable.other.property.v" }, "2": { "patterns": [ { "include": "#numbers" }, { "include": "#brackets" }, { "include": "#types" }, { "match": "\\w+", "name": "storage.type.other.v" } ] }, "3": { "name": "keyword.operator.assignment.v" }, "4": { "patterns": [ { "include": "$self" } ] } } }, { "include": "#types" }, { "include": "$self" } ] }, { "name": "meta.definition.struct.v", "match": "^\\s*(?:(mut|pub(?:\\s+mut)?|__global))\\s+?(struct)\\s+(?:\\s+([\\w.]+))?", "captures": { "1": { "name": "storage.modifier.$1.v" }, "2": { "name": "storage.type.struct.v" }, "3": { "name": "entity.name.struct.v" } } } ] }, "struct-access-modifier": { "match": "(?<=\\s|^)(mut|pub(?:\\s+mut)?|__global)(:|\\b)", "captures": { "1": { "name": "storage.modifier.$1.v" }, "2": { "name": "punctuation.separator.struct.key-value.v" } } }, "punctuation": { "patterns": [ { "name": "punctuation.delimiter.period.dot.v", "match": "\\." }, { "name": "punctuation.delimiter.comma.v", "match": "," }, { "name": "punctuation.separator.key-value.colon.v", "match": ":" }, { "name": "punctuation.definition.other.semicolon.v", "match": ";" }, { "name": "punctuation.definition.other.questionmark.v", "match": "\\?" }, { "name": "punctuation.hash.v", "match": "#" } ] }, "keywords": { "patterns": [ { "name": "keyword.control.v", "match": "(\\$if|\\$else)" }, { "name": "keyword.control.v", "match": "(?\\>|\\<\\<)" }, { "name": "keyword.operator.relation.v", "match": "(\\=\\=|\\!\\=|\\>|\\<|\\>\\=|\\<\\=)" }, { "name": "keyword.operator.assignment.v", "match": "(\\:\\=|\\=|\\+\\=|\\-\\=|\\*\\=|\\/\\=|\\%\\=|\\&\\=|\\|\\=|\\^\\=|\\~\\=|\\&\\&\\=|\\|\\|\\=|\\>\\>\\=|\\<\\<\\=)" }, { "name": "keyword.operator.bitwise.v", "match": "(\\&|\\||\\^|\\~|<(?!<)|>(?!>))" }, { "name": "keyword.operator.logical.v", "match": "(\\&\\&|\\|\\||\\!)" }, { "name": "keyword.operator.optional.v", "match": "\\?" } ] }, "numbers": { "patterns": [ { "name": "constant.numeric.exponential.v", "match": "([0-9]+(_?))+(\\.)([0-9]+[eE][-+]?[0-9]+)" }, { "name": "constant.numeric.float.v", "match": "([0-9]+(_?))+(\\.)([0-9]+)" }, { "name": "constant.numeric.binary.v", "match": "(?:0b)(?:(?:[0-1]+)(?:_?))+" }, { "name": "constant.numeric.octal.v", "match": "(?:0o)(?:(?:[0-7]+)(?:_?))+" }, { "name": "constant.numeric.hex.v", "match": "(?:0x)(?:(?:[0-9a-fA-F]+)(?:_?))+" }, { "name": "constant.numeric.integer.v", "match": "(?:(?:[0-9]+)(?:[_]?))+" } ] }, "punctuations": { "patterns": [ { "name": "punctuation.accessor.v", "match": "(?:\\.)" }, { "name": "punctuation.separator.comma.v", "match": "(?:,)" } ] }, "strings": { "patterns": [ { "begin": "`", "end": "`", "name": "string.quoted.rune.v", "patterns": [ { "include": "#string-escaped-char" }, { "include": "#string-interpolation" }, { "include": "#string-placeholder" } ] }, { "begin": "(r)'", "beginCaptures": { "1": { "name": "storage.type.string.v" } }, "end": "'", "name": "string.quoted.raw.v", "patterns": [ { "include": "#string-placeholder" } ] }, { "begin": "(r)\"", "beginCaptures": { "1": { "name": "storage.type.string.v" } }, "end": "\"", "name": "string.quoted.raw.v", "patterns": [ { "include": "#string-placeholder" } ] }, { "begin": "(c?)'", "beginCaptures": { "1": { "name": "storage.type.string.v" } }, "end": "'", "name": "string.quoted.v", "patterns": [ { "include": "#string-escaped-char" }, { "include": "#string-interpolation" }, { "include": "#string-placeholder" } ] }, { "begin": "(c?)\"", "beginCaptures": { "1": { "name": "storage.type.string.v" } }, "end": "\"", "name": "string.quoted.v", "patterns": [ { "include": "#string-escaped-char" }, { "include": "#string-interpolation" }, { "include": "#string-placeholder" } ] } ] }, "string-escaped-char": { "patterns": [ { "name": "constant.character.escape.v", "match": "\\\\([0-7]{3}|[\\$abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})" }, { "name": "invalid.illegal.unknown-escape.v", "match": "\\\\[^0-7\\$xuUabfnrtv\\'\"]" } ] }, "string-interpolation": { "patterns": [ { "name": "meta.string.interpolation.v", "begin": "(\\$\\{)", "beginCaptures": { "1": { "name": "punctuation.definition.template-expression.begin.v" } }, "end": "(\\})", "endCaptures": { "1": { "name": "punctuation.definition.template-expression.end.v" } }, "patterns": [ { "include": "#operators" }, { "include": "#numbers" }, { "include": "#function-exist" }, { "include": "#types" }, { "include": "#constants" }, { "match": "\\w+", "name": "variable.other.v" } ] } ] }, "string-placeholder": { "match": "%(\\[\\d+\\])?([\\+#\\-0\\x20]{,2}((\\d+|\\*)?(\\.?(\\d+|\\*|(\\[\\d+\\])\\*?)?(\\[\\d+\\])?)?))?[vT%tbcdoqxXUbeEfFgGsp]", "name": "constant.other.placeholder.v" }, "illegal-name": { "match": "\\d\\w+", "name": "invalid.illegal.v" } } } ================================================ FILE: tsconfig.json ================================================ { "compilerOptions": { "module": "ESNext", "moduleResolution": "bundler", "target": "ES6", "lib": ["ES2022", "DOM"], "baseUrl": "src", "outDir": "out", "rootDir": "src", "allowJs": true, "diagnostics": false, "esModuleInterop": true, "incremental": true, "noFallthroughCasesInSwitch": true, "noImplicitAny": true, "noImplicitOverride": true, "noImplicitReturns": true, "noImplicitThis": true, "noUncheckedIndexedAccess": true, "noUnusedLocals": false, "noUnusedParameters": false, "sourceMap": false, "stripInternal": true }, "include": ["src/**/*.ts"], "exclude": ["node_modules"] }