├── .env.template ├── .envrc ├── .github ├── dependabot.yml └── workflows │ ├── release-pr.yml │ └── test.yaml ├── .gitignore ├── .vscode-test.js ├── .vscode ├── launch.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── biome.json ├── bun.lock ├── commitlint.config.js ├── images ├── docs │ ├── linting.png │ ├── md-embed-nix.png │ └── nix-syntax-highlight.png ├── icon.png └── icon.svg ├── install.md ├── language-configuration.json ├── lefthook.yml ├── package.json ├── shell.nix ├── snippets.json ├── src ├── .gitignore ├── client.ts ├── configuration.ts ├── extension.test.ts ├── extension.ts ├── formatter.ts ├── global.d.ts ├── linter.ts ├── process-runner.ts └── utils.ts ├── syntaxes ├── .gitignore ├── injection.yml ├── nix.YAML-tmLanguage └── tests │ ├── bug-508.nix │ ├── bug-508.nix.snap │ ├── colon.nix │ ├── colon.nix.snap │ ├── colon2.nix │ ├── colon2.nix.snap │ ├── misc.nix │ ├── misc.nix.snap │ ├── sample.nix │ └── sample.nix.snap └── tsconfig.json /.env.template: -------------------------------------------------------------------------------- 1 | OVS_PAT= 2 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use nix -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Enable version updates for npm 4 | - package-ecosystem: "npm" 5 | # Look for `package.json` and `lock` files in the `root` directory 6 | directory: "/" 7 | # Check the npm registry for updates every week (weekdays) 8 | schedule: 9 | interval: "monthly" 10 | groups: 11 | production-dependencies: 12 | dependency-type: 'production' 13 | development-dependencies: 14 | dependency-type: 'development' 15 | 16 | - package-ecosystem: 'github-actions' 17 | directory: '/' 18 | schedule: 19 | interval: 'monthly' -------------------------------------------------------------------------------- /.github/workflows/release-pr.yml: -------------------------------------------------------------------------------- 1 | name: Release PR 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | version-bump: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: write 13 | pull-requests: write 14 | 15 | steps: 16 | - uses: actions/checkout@v5 17 | with: 18 | fetch-depth: 0 19 | - name: Configure Git 20 | run: | 21 | git config --global user.name 'GitHub Actions' 22 | git config --global user.email 'actions@github.com' 23 | - name: Check Commit Message 24 | id: check_commit 25 | run: | 26 | commit_message=$(git log -1 --pretty=%B) 27 | if [[ "$commit_message" =~ ^chore\(release\):\ ([.0-9]+).* ]]; then 28 | version="${BASH_REMATCH[1]}" 29 | echo "is_release=true" >> $GITHUB_OUTPUT 30 | echo "version=$version" >> $GITHUB_OUTPUT 31 | else 32 | echo "is_release=false" >> $GITHUB_OUTPUT 33 | fi 34 | - uses: oven-sh/setup-bun@v2 35 | - name: generate changelog and bump version 36 | if: steps.check_commit.outputs.is_release == 'false' 37 | run: bunx standard-version 38 | - name: Create Pull Request 39 | if: steps.check_commit.outputs.is_release == 'false' 40 | uses: peter-evans/create-pull-request@v7 41 | with: 42 | title: "Pending Release" 43 | body: "Automated version bump using standard-version" 44 | branch: version-bump 45 | delete-branch: true 46 | base: main 47 | - name: tag current package version and push 48 | if: steps.check_commit.outputs.is_release == 'true' 49 | run: | 50 | git tag v${{ steps.check_commit.outputs.version }} || true 51 | git push --tags || true 52 | bun install --frozen-lockfile 53 | bun run package 54 | bun run ovsx publish *.vsix --pat ${{ secrets.OPEN_VSX_TOKEN }} || true 55 | bun run vsce publish -p ${{ secrets.VS_MARKETPLACE_TOKEN }} || true 56 | gh release create v${{ steps.check_commit.outputs.version }} nix-ide*.vsix --title "v${{ steps.check_commit.outputs.version }}" --notes "Release v${{ steps.check_commit.outputs.version }}" 57 | env: 58 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 59 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: [master, main] 6 | pull_request: 7 | branches: [master, main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.os }} 12 | 13 | strategy: 14 | matrix: 15 | os: [ubuntu-latest, macos-latest, windows-latest] 16 | 17 | steps: 18 | - uses: actions/checkout@v5 19 | - uses: oven-sh/setup-bun@v2 20 | - run: bun install 21 | - run: bun run lint 22 | - run: bun run build 23 | - run: bun run pretest 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/* 2 | !.vscode/settings.json 3 | !.vscode/tasks.json 4 | !.vscode/launch.json 5 | !.vscode/extensions.json 6 | *.code-workspace 7 | 8 | # Local History for Visual Studio Code 9 | .history/ 10 | 11 | # Logs 12 | logs 13 | *.log 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | lerna-debug.log* 18 | 19 | # Diagnostic reports (https://nodejs.org/api/report.html) 20 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 21 | 22 | # Runtime data 23 | pids 24 | *.pid 25 | *.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | lib-cov 30 | 31 | # Coverage directory used by tools like istanbul 32 | coverage 33 | *.lcov 34 | 35 | # nyc test coverage 36 | .nyc_output 37 | 38 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 39 | .grunt 40 | 41 | # Bower dependency directory (https://bower.io/) 42 | bower_components 43 | 44 | # node-waf configuration 45 | .lock-wscript 46 | 47 | # Compiled binary addons (https://nodejs.org/api/addons.html) 48 | build/Release 49 | 50 | # Dependency directories 51 | node_modules/ 52 | jspm_packages/ 53 | 54 | # Snowpack dependency directory (https://snowpack.dev/) 55 | web_modules/ 56 | 57 | # TypeScript cache 58 | *.tsbuildinfo 59 | 60 | # Optional npm cache directory 61 | .npm 62 | 63 | # Optional eslint cache 64 | .eslintcache 65 | 66 | # Microbundle cache 67 | .rpt2_cache/ 68 | .rts2_cache_cjs/ 69 | .rts2_cache_es/ 70 | .rts2_cache_umd/ 71 | 72 | # Optional REPL history 73 | .node_repl_history 74 | 75 | # Output of 'npm pack' 76 | *.tgz 77 | 78 | # Yarn Integrity file 79 | .yarn-integrity 80 | 81 | # dotenv environment variables file 82 | .env 83 | .env.test 84 | 85 | # parcel-bundler cache (https://parceljs.org/) 86 | .cache 87 | .parcel-cache 88 | 89 | # Next.js build output 90 | .next 91 | out 92 | 93 | # Nuxt.js build / generate output 94 | .nuxt 95 | dist 96 | 97 | # Gatsby files 98 | .cache/ 99 | # Comment in the public line in if your project uses Gatsby and not Next.js 100 | # https://nextjs.org/blog/next-9-1#public-directory-support 101 | # public 102 | 103 | # vuepress build output 104 | .vuepress/dist 105 | 106 | # Serverless directories 107 | .serverless/ 108 | 109 | # FuseBox cache 110 | .fusebox/ 111 | 112 | # DynamoDB Local files 113 | .dynamodb/ 114 | 115 | # TernJS port file 116 | .tern-port 117 | 118 | # Stores VSCode versions used for testing VSCode extensions 119 | .vscode-test 120 | 121 | # yarn v2 122 | .yarn/cache 123 | .yarn/unplugged 124 | .yarn/build-state.yml 125 | .yarn/install-state.gz 126 | .pnp.* 127 | 128 | .fake 129 | .ionide 130 | 131 | # latest paket versions 132 | .paket/ 133 | paket-files/ 134 | 135 | *.vsix 136 | 137 | # some misc. proj. files 138 | .local/ 139 | .DS_Store 140 | .direnv/ 141 | .husky/ 142 | -------------------------------------------------------------------------------- /.vscode-test.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('@vscode/test-cli'); 2 | 3 | module.exports = defineConfig({ files: 'out/src/**/*.test.ts', mocha: { ui: 'bdd' } }); 4 | -------------------------------------------------------------------------------- /.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": "Launch with Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "preLaunchTask": "Bun Debug Build", 14 | "args": [ 15 | "--extensionDevelopmentPath=${workspaceFolder}" 16 | ], 17 | "outFiles": [ 18 | "${workspaceRoot}/dist/**/*.js" 19 | ] 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Bun Debug Build", 6 | "type": "shell", 7 | "command": "bun run build --sourcemap", 8 | "options": { 9 | "cwd": "${workspaceFolder}" 10 | }, 11 | "group": "build", 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | # Ignore everything 2 | * 3 | */** 4 | 5 | # Whitelist what you need 6 | !.vscodeignore 7 | !dist/* 8 | !images/* 9 | !language-configuration.json 10 | !LICENSE 11 | !snippets.json 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ## [0.5.0](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.24...v0.5.0) (2025-10-10) 6 | 7 | 8 | ### ⚠ BREAKING CHANGES 9 | 10 | * remove special highlight of comment remarks like todo/fixme 11 | 12 | ### Features 13 | 14 | * allow "serverPath" to be a list of arguments ([#509](https://github.com/nix-community/vscode-nix-ide/issues/509)) ([6a1835a](https://github.com/nix-community/vscode-nix-ide/commit/6a1835a5b5c85b1d9de4fbf2480b315095a19a30)) 15 | * **manifest:** provide `flake.lock` format ([#507](https://github.com/nix-community/vscode-nix-ide/issues/507)) ([79876a0](https://github.com/nix-community/vscode-nix-ide/commit/79876a0fa762968a9816235f0bcf88c91a7640dd)) 16 | 17 | 18 | ### Bug Fixes 19 | 20 | * **syntax:** syntax highlighting issue with colon after interpolation in nested attrset ([aa8a59d](https://github.com/nix-community/vscode-nix-ide/commit/aa8a59d845efa5bbe69713dfddadd345611e632b)), closes [#355](https://github.com/nix-community/vscode-nix-ide/issues/355) 21 | 22 | 23 | * remove special highlight of comment remarks like todo/fixme ([fe0a576](https://github.com/nix-community/vscode-nix-ide/commit/fe0a5763cbe937ffcb00846b053b9928fc919f7e)), closes [#476](https://github.com/nix-community/vscode-nix-ide/issues/476) 24 | 25 | ### [0.4.24](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.23...v0.4.24) (2025-09-29) 26 | 27 | 28 | ### Features 29 | 30 | * set explorer.fileNesting for flake.lock ([#498](https://github.com/nix-community/vscode-nix-ide/issues/498)) ([05b33f2](https://github.com/nix-community/vscode-nix-ide/commit/05b33f2c4c8ca266b02b99fa2771810c7393e649)) 31 | 32 | 33 | ### Bug Fixes 34 | 35 | * vscode debug launch ([#500](https://github.com/nix-community/vscode-nix-ide/issues/500)) ([620cb85](https://github.com/nix-community/vscode-nix-ide/commit/620cb855221e4f310dc8e470ac366139ad243e1c)) 36 | 37 | ### [0.4.23](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.22...v0.4.23) (2025-09-16) 38 | 39 | 40 | ### Bug Fixes 41 | 42 | * nix file icon off center in VS code ([#495](https://github.com/nix-community/vscode-nix-ide/issues/495)) ([fc62423](https://github.com/nix-community/vscode-nix-ide/commit/fc62423d9f8f92dace4b6e70b0d83b9f0e728131)) 43 | 44 | ### [0.4.22](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.21...v0.4.22) (2025-06-29) 45 | 46 | 47 | ### Features 48 | 49 | * add backticks to surroundingPairs ([#491](https://github.com/nix-community/vscode-nix-ide/issues/491)) ([b8744ab](https://github.com/nix-community/vscode-nix-ide/commit/b8744ab40ca31a2012a9238d063a3d4bacfbde7c)) 50 | 51 | ### [0.4.21](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.20...v0.4.21) (2025-06-20) 52 | 53 | ### [0.4.20](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.19...v0.4.20) (2025-06-20) 54 | 55 | ### [0.4.19](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.18...v0.4.19) (2025-06-20) 56 | 57 | 58 | ### Features 59 | 60 | * add semantic token default scopes for nil ([#487](https://github.com/nix-community/vscode-nix-ide/issues/487)) ([48d4934](https://github.com/nix-community/vscode-nix-ide/commit/48d493465c67890a035090ea861548a49f6108dd)) 61 | 62 | ### [0.4.18](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.17...v0.4.18) (2025-05-19) 63 | 64 | 65 | ### Bug Fixes 66 | 67 | * add auto-indent for multi-line strings ([#480](https://github.com/nix-community/vscode-nix-ide/issues/480)) ([1ff3ff0](https://github.com/nix-community/vscode-nix-ide/commit/1ff3ff0a6c769bffba1308731fb81dbe81a39378)) 68 | 69 | ### [0.4.17](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.16...v0.4.17) (2025-05-19) 70 | 71 | 72 | ### Features 73 | 74 | * auto-indent on pressed enter ([#477](https://github.com/nix-community/vscode-nix-ide/issues/477)) ([0c49e90](https://github.com/nix-community/vscode-nix-ide/commit/0c49e907c5537d04adde8e25e94f514adeca20d8)) 75 | 76 | 77 | ### Bug Fixes 78 | 79 | * clarify descriptions of formatter settings ([#478](https://github.com/nix-community/vscode-nix-ide/issues/478)) ([4afa347](https://github.com/nix-community/vscode-nix-ide/commit/4afa3478570787c1e30cc7bea90543173be7fa21)) 80 | * shell.nix with bun instead of yarn (fixes [#473](https://github.com/nix-community/vscode-nix-ide/issues/473)) ([#474](https://github.com/nix-community/vscode-nix-ide/issues/474)) ([62b6e93](https://github.com/nix-community/vscode-nix-ide/commit/62b6e939ddac903a65273d2fc926619a724c86c8)) 81 | 82 | ### [0.4.16](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.15...v0.4.16) (2025-03-18) 83 | 84 | ### [0.4.15](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.14...v0.4.15) (2025-03-18) 85 | 86 | ### [0.4.14](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.13...v0.4.14) (2025-03-18) 87 | 88 | ### [0.4.13](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.12...v0.4.13) (2025-03-18) 89 | 90 | 91 | ### Bug Fixes 92 | 93 | * issue warning on missing `nil`/`nixd` ([#465](https://github.com/nix-community/vscode-nix-ide/issues/465)) ([2cb1d94](https://github.com/nix-community/vscode-nix-ide/commit/2cb1d94f6738efced607e772e0ea5c77b9fc7701)) 94 | 95 | ### [0.4.12](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.11...v0.4.12) (2025-02-02) 96 | 97 | 98 | ### Features 99 | 100 | * add pipe operators ([#458](https://github.com/nix-community/vscode-nix-ide/issues/458)) ([ac1ed65](https://github.com/nix-community/vscode-nix-ide/commit/ac1ed65aa92655748200cd62bd54e5ca051781bc)) 101 | 102 | ### [0.4.11](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.10...v0.4.11) (2025-01-26) 103 | 104 | 105 | ### Features 106 | 107 | * add predefined formatters ([0352918](https://github.com/nix-community/vscode-nix-ide/commit/0352918d9a3dc14af18fd656e11e970c8efd0bf0)) 108 | 109 | 110 | ### Bug Fixes 111 | 112 | * build as cjs module ([1952078](https://github.com/nix-community/vscode-nix-ide/commit/1952078345ab0e2fedbde694a81c6e194d377545)), closes [#453](https://github.com/nix-community/vscode-nix-ide/issues/453) 113 | 114 | ### [0.4.10](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.9...v0.4.10) (2025-01-24) 115 | 116 | ### [0.4.9](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.8...v0.4.9) (2025-01-24) 117 | 118 | ### [0.4.8](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.7...v0.4.8) (2025-01-24) 119 | 120 | ### [0.4.7](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.6...v0.4.7) (2025-01-24) 121 | 122 | 123 | ### Bug Fixes 124 | 125 | * automated release by PR ([d9d9070](https://github.com/nix-community/vscode-nix-ide/commit/d9d90704701145f350d6f6ed747d95f8dc33d301)) 126 | 127 | ### [0.4.6](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.5...v0.4.6) (2025-01-24) 128 | 129 | ### [0.4.5](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.3...v0.4.5) (2025-01-24) 130 | 131 | ### [0.4.4](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.2...v0.4.4) (2025-01-24) 132 | 133 | 134 | ### Features 135 | 136 | * do not package syntax *yml files ([ce091fb](https://github.com/nix-community/vscode-nix-ide/commit/ce091fbab288407dfa678dbba8f1b84ce2bfda38)) 137 | * replace esbuild with `bun build` ([20c7eb3](https://github.com/nix-community/vscode-nix-ide/commit/20c7eb3174a0d151abee22d9252dbd8ea4d65a54)) 138 | * use bun v1.2 text lockfiles ([da6fd4d](https://github.com/nix-community/vscode-nix-ide/commit/da6fd4dfb64b766bca9aaff70bf3cd9a2fb6a5b2)) 139 | 140 | ### [0.4.3](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.2...v0.4.3) (2025-01-24) 141 | 142 | 143 | ### Features 144 | 145 | * do not package syntax *yml files ([ce091fb](https://github.com/nix-community/vscode-nix-ide/commit/ce091fbab288407dfa678dbba8f1b84ce2bfda38)) 146 | * replace esbuild with `bun build` ([20c7eb3](https://github.com/nix-community/vscode-nix-ide/commit/20c7eb3174a0d151abee22d9252dbd8ea4d65a54)) 147 | * use bun v1.2 text lockfiles ([da6fd4d](https://github.com/nix-community/vscode-nix-ide/commit/da6fd4dfb64b766bca9aaff70bf3cd9a2fb6a5b2)) 148 | 149 | ## [0.4.2](https://github.com/nix-community/vscode-nix-ide/compare/v0.4.1...v0.4.2) (2025-01-17) 150 | 151 | 152 | ### Features 153 | 154 | * remove unused dependencies ([0a842f6](https://github.com/nix-community/vscode-nix-ide/commit/0a842f6687dedb1a7a1ac0fdfde06e390aab6042)) 155 | 156 | ## [0.4.0](https://github.com/nix-community/vscode-nix-ide/compare/v0.3.7...v0.4.0) (2025-01-17) 157 | 158 | 159 | ### Features 160 | 161 | * add grammar test ([018be88](https://github.com/nix-community/vscode-nix-ide/commit/018be88ba0d6d0104e9d57b9250bb36c84ea52ed)) 162 | * add initial integration test ([e25320f](https://github.com/nix-community/vscode-nix-ide/commit/e25320f9e6c2979d94b05c7ef09fd5380d74de71)) 163 | * add release-please action ([50b5921](https://github.com/nix-community/vscode-nix-ide/commit/50b59213beb401641d8ae17bcd4d6e4ef1e28815)) 164 | 165 | 166 | ### Bug Fixes 167 | 168 | * default to nixfmt formatter ([#441](https://github.com/nix-community/vscode-nix-ide/issues/441)) ([582c364](https://github.com/nix-community/vscode-nix-ide/commit/582c3642df2188c3096ac646c575e386ae04923e)) 169 | 170 | ## [0.3.7](https://github.com/nix-community/vscode-nix-ide/compare/v0.3.6...v0.3.7) (2025-01-16) 171 | 172 | 173 | ### Bug Fixes 174 | 175 | * biome linter fixes ([e5c15ed](https://github.com/nix-community/vscode-nix-ide/commit/e5c15edad557f08f69178d466a42201c753d4e6d)) 176 | 177 | ## [0.3.6](https://github.com/nix-community/vscode-nix-ide/compare/v0.3.5...v0.3.6) (2024-09-20) 178 | 179 | 180 | ### Features 181 | 182 | * delay activation ([#424](https://github.com/nix-community/vscode-nix-ide/issues/424)) ([7038804](https://github.com/nix-community/vscode-nix-ide/commit/7038804b9e06d04df254fc4b516363a53a7f063e)) 183 | 184 | ### [0.3.5](https://github.com/nix-community/vscode-nix-ide/compare/v0.3.4...v0.3.5) (2024-09-13) 185 | 186 | 187 | ### Bug Fixes 188 | 189 | * reload language server client on restart ([#420](https://github.com/nix-community/vscode-nix-ide/issues/420)) ([4c48cb0](https://github.com/nix-community/vscode-nix-ide/commit/4c48cb06cddf439f65d6ec066f41c6a6432ffa5a)), closes [#419](https://github.com/nix-community/vscode-nix-ide/issues/419) 190 | 191 | ### [0.3.4](https://github.com/nix-community/vscode-nix-ide/compare/v0.3.3...v0.3.4) (2024-09-10) 192 | 193 | 194 | ### Features 195 | 196 | * add setting to suppress error notifications ([4913819](https://github.com/nix-community/vscode-nix-ide/commit/4913819384f2fe70e15ea7c814a739926a5d1280)) 197 | 198 | ### [0.3.3](https://github.com/nix-community/vscode-nix-ide/compare/v0.3.2...v0.3.3) (2024-08-02) 199 | 200 | 201 | ### Bug Fixes 202 | 203 | * vsce latest ([cecea30](https://github.com/nix-community/vscode-nix-ide/commit/cecea3041cfdb0aebc6c7e6c02dfeca193c360d6)) 204 | 205 | ### [0.3.2](https://github.com/nix-community/vscode-nix-ide/compare/v0.3.1...v0.3.2) (2024-08-02) 206 | 207 | 208 | ### Features 209 | 210 | * add restarting language server command ([#381](https://github.com/nix-community/vscode-nix-ide/issues/381)) ([c52dc29](https://github.com/nix-community/vscode-nix-ide/commit/c52dc292a7d3b356bc1a18d31f9df8395770d679)) 211 | * migrate eslint config ([5fd26eb](https://github.com/nix-community/vscode-nix-ide/commit/5fd26eb00f6c3c9fabbf9fce4c43b6259fa6d1ed)) 212 | * support use vscode variables in settings ([#399](https://github.com/nix-community/vscode-nix-ide/issues/399)) ([a602050](https://github.com/nix-community/vscode-nix-ide/commit/a6020509005221a0bb885b2d5914fd8f4563f97d)) 213 | 214 | 215 | ### Bug Fixes 216 | 217 | * dependabot config ([df48657](https://github.com/nix-community/vscode-nix-ide/commit/df4865707169754900a2f609eacd38f82586b8ed)) 218 | * eslint errors ([de74fc2](https://github.com/nix-community/vscode-nix-ide/commit/de74fc218d73fbb22fe97708a666798dee35335f)) 219 | 220 | ### [0.3.1](https://github.com/nix-community/vscode-nix-ide/compare/v0.3.0...v0.3.1) (2024-03-12) 221 | 222 | ## [0.3.0](https://github.com/nix-community/vscode-nix-ide/compare/v0.2.2...v0.3.0) (2024-03-12) 223 | 224 | 225 | ### ⚠ BREAKING CHANGES 226 | 227 | * upgrade dependencies 228 | 229 | * upgrade dependencies ([3778ed6](https://github.com/nix-community/vscode-nix-ide/commit/3778ed648f1a0f73b8826860f591ab7b9e9bb355)) 230 | 231 | ### [0.2.2](https://github.com/nix-community/vscode-nix-ide/compare/v0.2.1...v0.2.2) (2023-07-26) 232 | 233 | 234 | ### Features 235 | 236 | * set file icon ([f7c2244](https://github.com/nix-community/vscode-nix-ide/commit/f7c22449ca7de99a6421a9694c606486eee607a8)) 237 | 238 | ### [0.2.1](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.23...v0.2.1) (2022-10-14) 239 | 240 | 241 | ### Features 242 | 243 | * declare support for nil ([#276](https://github.com/nix-community/vscode-nix-ide/issues/276)) ([c19ceba](https://github.com/nix-community/vscode-nix-ide/commit/c19ceba897f4e23aba6bad543a16ee901f4195f6)) 244 | * passing settings to lsp ([#294](https://github.com/nix-community/vscode-nix-ide/issues/294)) ([c898347](https://github.com/nix-community/vscode-nix-ide/commit/c89834791c8eb8230cd5d07d3754bdb30ed8b822)) 245 | 246 | ### [0.1.24](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.23...v0.1.24) (2022-10-14) 247 | 248 | ### [0.1.23](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.22...v0.1.23) (2022-08-16) 249 | 250 | 251 | ### Features 252 | 253 | * add nix-shell and direnv support ([#251](https://github.com/nix-community/vscode-nix-ide/issues/251)) ([d78b62d](https://github.com/nix-community/vscode-nix-ide/commit/d78b62ded8e575c01922ff781884af026578c7a4)) 254 | 255 | 256 | ### Bug Fixes 257 | 258 | * catch error if serverPath doesn't exist ([#267](https://github.com/nix-community/vscode-nix-ide/issues/267)) ([95caf81](https://github.com/nix-community/vscode-nix-ide/commit/95caf810a2f0415103ebc5c3dfde7b78729be4c3)) 259 | 260 | ### [0.1.22](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.20...v0.1.22) (2022-08-14) 261 | 262 | 263 | ### Bug Fixes 264 | 265 | * mark interpolation as meta.embedded instead of markup.italic ([cd420d0](https://github.com/nix-community/vscode-nix-ide/commit/cd420d0bcea26cf1cf650f47c738bd1b6658a80c)) 266 | 267 | ### [0.1.21](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.20...v0.1.21) (2022-08-14) 268 | 269 | 270 | ### Bug Fixes 271 | 272 | * mark interpolation as meta.embedded instead of markup.italic ([cd420d0](https://github.com/nix-community/vscode-nix-ide/commit/cd420d0bcea26cf1cf650f47c738bd1b6658a80c)) 273 | 274 | ### [0.1.20](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.19...v0.1.20) (2022-02-23) 275 | 276 | ### [0.1.19](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.18...v0.1.19) (2022-01-02) 277 | 278 | 279 | ### Features 280 | 281 | * antiquotation brackets ([55e9258](https://github.com/nix-community/vscode-nix-ide/commit/55e92589b9b73eda3314a7b14e059c0ff77a1bfb)) 282 | * path angle brackets ([f79b542](https://github.com/nix-community/vscode-nix-ide/commit/f79b54226f2ad5a6ddbe968c632c4c75b2141974)) 283 | * word pattern ([d1389f6](https://github.com/nix-community/vscode-nix-ide/commit/d1389f6c479ceee7813635f793d7d3c02e27329c)) 284 | 285 | 286 | ### Bug Fixes 287 | 288 | * auto close at end of string ([ae0c981](https://github.com/nix-community/vscode-nix-ide/commit/ae0c981de0a60a5910dca472643bbbf43ef51c63)) 289 | * auto close double quotes in comments ([aab9cef](https://github.com/nix-community/vscode-nix-ide/commit/aab9ceffa3e52a4938b5907697b7edadd51069fb)) 290 | * don't auto close single quotes ([c912fc8](https://github.com/nix-community/vscode-nix-ide/commit/c912fc8c128c0bc1c4600ae2aa904237cb13e780)) 291 | * folding marker comments ([bab9fdf](https://github.com/nix-community/vscode-nix-ide/commit/bab9fdfcbb2ae2fcceb8c11cec2c1e96d6f14c45)) 292 | * quotes inside attributes ([b003401](https://github.com/nix-community/vscode-nix-ide/commit/b0034014a1b96ac862e4ff678e2f93917fdd7f91)), closes [#189](https://github.com/nix-community/vscode-nix-ide/issues/189) 293 | * update branch names in ci configs ([66e6991](https://github.com/nix-community/vscode-nix-ide/commit/66e69919cf84fd4465378368a8525a935ce9c81a)) 294 | 295 | ### [0.1.18](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.17...v0.1.18) (2021-10-12) 296 | 297 | ### [0.1.17](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.16...v0.1.17) (2021-10-12) 298 | 299 | 300 | ### Features 301 | 302 | * make the formatter path configurable ([03c25cb](https://github.com/nix-community/vscode-nix-ide/commit/03c25cb57dc36cf23dd2641abe3d34fbec01eb4a)) 303 | 304 | 305 | ### Bug Fixes 306 | 307 | * release to ovsx registry ([b07688e](https://github.com/nix-community/vscode-nix-ide/commit/b07688ec19d97337be8e8b1371e911b6b908884a)) 308 | 309 | ### [0.1.16](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.15...v0.1.16) (2021-08-20) 310 | 311 | 312 | ### Features 313 | 314 | * add esbuild bundling ([2ee7a3f](https://github.com/nix-community/vscode-nix-ide/commit/2ee7a3f99e25c895fa39be3cde210d7a748d4bee)) 315 | 316 | ### [0.1.15](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.14...v0.1.15) (2021-08-16) 317 | 318 | ### [0.1.14](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.13...v0.1.14) (2021-08-16) 319 | 320 | 321 | ### Features 322 | 323 | * upgrade dependencies to latest versions ([072b823](https://github.com/nix-community/vscode-nix-ide/commit/072b823d1f8fa6a55a870a94233e44af6ee14e57)) 324 | 325 | ### [0.1.13](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.12...v0.1.13) (2021-08-16) 326 | 327 | ### [0.1.12](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.11...v0.1.12) (2021-05-08) 328 | 329 | ### [0.1.11](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.10...v0.1.11) (2021-05-08) 330 | 331 | 332 | ### Features 333 | 334 | * **linter:** Allow symbol errors to show (static analysys) ([041dffc](https://github.com/nix-community/vscode-nix-ide/commit/041dffc92fae798c41ed211ee805ee6ce5772c5f)) 335 | 336 | ### [0.1.10](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.9...v0.1.10) (2021-03-24) 337 | 338 | ### [0.1.9](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.8...v0.1.9) (2021-03-24) 339 | 340 | ### [0.1.8](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.7...v0.1.8) (2020-12-23) 341 | 342 | 343 | ### Features 344 | 345 | * create vsix artifacts part of release ([6e2c1fe](https://github.com/nix-community/vscode-nix-ide/commit/6e2c1fe962744936669b47a5b42b57f6d19b304c)) 346 | 347 | ### [0.1.7](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.6...v0.1.7) (2020-12-23) 348 | 349 | ### [0.1.6](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.5...v0.1.6) (2020-12-23) 350 | 351 | 352 | ### Features 353 | 354 | * add rnix LSP support ([ec3dee3](https://github.com/nix-community/vscode-nix-ide/commit/ec3dee34ba273d181593e647f305de10d54e5e10)), closes [#10](https://github.com/nix-community/vscode-nix-ide/issues/10) 355 | * check rnix-lsp and suggest if not installed ([e09563f](https://github.com/nix-community/vscode-nix-ide/commit/e09563f849fd7cb9d28c688a1c0c3bd2da890041)) 356 | 357 | 358 | ### Bug Fixes 359 | 360 | * since update to lsp-client v7 ([e3fa686](https://github.com/nix-community/vscode-nix-ide/commit/e3fa686464dcac5319ddae5a5d23904c4f5bc487)) 361 | 362 | ### [0.1.5](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.3...v0.1.5) (2020-10-24) 363 | 364 | ### [0.1.3](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.2...v0.1.3) (2020-08-16) 365 | 366 | ### [0.1.2](https://github.com/nix-community/vscode-nix-ide/compare/v0.1.1...v0.1.2) (2020-08-16) 367 | 368 | ### 0.1.1 (2020-08-16) 369 | 370 | 371 | ### Features 372 | 373 | * add fable to project ([e7b4962](https://github.com/nix-community/vscode-nix-ide/commit/e7b49622ed06a2ad7d9bb7d69ed5a1ef6d0af9e5)) 374 | * add license info ([f559fc3](https://github.com/nix-community/vscode-nix-ide/commit/f559fc3cd41980d698fb62a18c5f4b636d32c403)) 375 | * add linter for nix files with nix-instantiate ([cbf6abe](https://github.com/nix-community/vscode-nix-ide/commit/cbf6abef33a948bdbc5c9c54019e93d0320ba965)) 376 | * adding basic snippets ([02e1995](https://github.com/nix-community/vscode-nix-ide/commit/02e199541e6db1f74c6a2de680957f81a9afa498)) 377 | * initial commit ([35d49df](https://github.com/nix-community/vscode-nix-ide/commit/35d49df84975c0f3940173f0be517f5bc94528b3)) 378 | * markdown embedded support ([4debbfd](https://github.com/nix-community/vscode-nix-ide/commit/4debbfd90884930c5e7f5d49141fd5017dd23d56)) 379 | * update language configuration ([188c9cf](https://github.com/nix-community/vscode-nix-ide/commit/188c9cfecbcf5b8cb73f1c98ba9435eb68c394b6)) 380 | 381 | 382 | ### Bug Fixes 383 | 384 | * syntax file name ([3113b30](https://github.com/nix-community/vscode-nix-ide/commit/3113b3073f1ec62bed8a4eddc9cb7dab994b97c9)) 385 | 386 | ### 0.0.2 (2020-08-16) 387 | 388 | 389 | ### Features 390 | 391 | * add fable to project ([e7b4962](https://github.com/nix-community/vscode-nix-ide/commit/e7b49622ed06a2ad7d9bb7d69ed5a1ef6d0af9e5)) 392 | * add license info ([f559fc3](https://github.com/nix-community/vscode-nix-ide/commit/f559fc3cd41980d698fb62a18c5f4b636d32c403)) 393 | * add linter for nix files with nix-instantiate ([cbf6abe](https://github.com/nix-community/vscode-nix-ide/commit/cbf6abef33a948bdbc5c9c54019e93d0320ba965)) 394 | * adding basic snippets ([02e1995](https://github.com/nix-community/vscode-nix-ide/commit/02e199541e6db1f74c6a2de680957f81a9afa498)) 395 | * initial commit ([35d49df](https://github.com/nix-community/vscode-nix-ide/commit/35d49df84975c0f3940173f0be517f5bc94528b3)) 396 | * markdown embedded support ([4debbfd](https://github.com/nix-community/vscode-nix-ide/commit/4debbfd90884930c5e7f5d49141fd5017dd23d56)) 397 | * update language configuration ([188c9cf](https://github.com/nix-community/vscode-nix-ide/commit/188c9cfecbcf5b8cb73f1c98ba9435eb68c394b6)) 398 | 399 | 400 | ### Bug Fixes 401 | 402 | * syntax file name ([3113b30](https://github.com/nix-community/vscode-nix-ide/commit/3113b3073f1ec62bed8a4eddc9cb7dab994b97c9)) 403 | 404 | # Change Log 405 | 406 | All notable changes to the "nix" extension will be documented in this file. 407 | 408 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 409 | 410 | ## [Unreleased] 411 | 412 | - Initial release 413 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | - Document the purpose of functions and classes. 4 | - Please mention new features in the `README.md` features section. Use screenshots when applicable. 5 | - The [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) style should be used for commit messages as it is used to generate the changelog. 6 | 7 | ## Development 8 | 9 | There is [direnv](https://direnv.net/) and [nix-shell](https://nixos.wiki/wiki/Development_environment_with_nix-shell) support so a dev environment can be created with the `nix-shell` command or a one-time `direnv allow` at the root of the repo. 10 | 11 | Press `F5` in VSCode to run an Extension Development Host instance with the extension installed. 12 | 13 | TypeScript is used to develop the extension. 14 | 15 | ```sh 16 | bun install # install dependencies 17 | bun run build # build the extension 18 | ``` 19 | 20 | ## Releasing a new version 21 | 22 | Complete `.env` with environment variables based on `.env.template`, 23 | 24 | ```sh 25 | # this will generate changelog and will create a GitHub release. This will also trigger jobs to publish the extension. 26 | bun run release 27 | 28 | # to manually publish the extension 29 | bun run publish 30 | ``` 31 | 32 | # VS Code Extension Quickstart 33 | 34 | ## What's in the folder 35 | 36 | * This folder contains all of the files necessary for your extension. 37 | * `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension. 38 | * `syntaxes/nix.YAML-tmLanguage` - this is the Text mate grammar file that is used for tokenization. This will get compiled to `syntaxes/nix.tmLanguage.json` during build. 39 | * `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets. 40 | 41 | ## Get up and running straight away 42 | 43 | * Make sure the language configuration settings in `language-configuration.json` are accurate. 44 | * Press `F5` to open a new window with your extension loaded. 45 | * Create a new file with a file name suffix matching your language. 46 | * Verify that syntax highlighting works and that the language configuration settings are working. 47 | 48 | ## Make changes 49 | 50 | * You can relaunch the extension from the debug toolbar after making changes to the files listed above. 51 | * You can also reload ( `Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 52 | 53 | ## Add more language features 54 | 55 | * To add features such as intellisense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs 56 | 57 | ## Install your extension 58 | 59 | * To start using your extension with Visual Studio Code copy it into the `/.vscode/extensions` folder and restart Code. 60 | * To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension. 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 noor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nix IDE ✨💡🌟 2 | 3 | Adds [Nix](https://nixos.org/) language support for [Visual Studio Code](https://code.visualstudio.com/). 4 | 5 | ## Quickstart 🚀 6 | 7 | 1. [Install](./install.md) the extension, and open a Nix file. 8 | 1. [Syntax highlighting](./images/docs/nix-syntax-highlight.png) should work out of the box. Nix code blocks inside `markdown` files are also [supported](./images/docs/md-embed-nix.png). 9 | 1. Auto-formatting should work if [`nixfmt`](https://github.com/NixOS/nixfmt) is available in `$PATH`. A custom formatter can be set by [configuring `nix.formatterPath`](#custom-formatter). 10 | 1. Syntax errors are [linted](./images/docs/linting.png) using `nix-instantiate`. 11 | 1. Full language support can be enabled by configuring a language server. See [LSP Plugin Support](#lsp-plugin-support) for more information. 12 | 1. Snippets are provided for conditional expressions, `let`/`with` expressions, and `rec`ursive sets. 13 | 1. Path completion is supported using the [Path Intellisense](https://github.com/ChristianKohler/PathIntellisense) extension. 14 | 15 | ## Settings ⚙️ 16 | 17 | ### LSP Plugin Support 18 | 19 | Full language support can be enabled by using a language server. Generally, any Nix [LSP](https://microsoft.github.io/language-server-protocol/) implementation should work. Some examples are given below for [`nil`](https://github.com/oxalica/nil?tab=readme-ov-file#vscodevscodium-with-nix-ide) and [`nixd`](https://github.com/nix-community/nixd). 20 | 21 | ```json5 22 | { 23 | "nix.enableLanguageServer": true, 24 | "nix.serverPath": "nil", // or "nixd", or ["executable", "argument1", ...] 25 | // LSP config can be passed via the ``nix.serverSettings.{lsp}`` as shown below. 26 | "nix.serverSettings": { 27 | // check https://github.com/oxalica/nil/blob/main/docs/configuration.md for all options available 28 | "nil": { 29 | // "diagnostics": { 30 | // "ignored": ["unused_binding", "unused_with"], 31 | // }, 32 | "formatting": { 33 | "command": ["nixfmt"], 34 | }, 35 | }, 36 | // check https://github.com/nix-community/nixd/blob/main/nixd/docs/configuration.md for all nixd config 37 | "nixd": { 38 | "formatting": { 39 | "command": ["nixfmt"], 40 | }, 41 | "options": { 42 | // By default, this entry will be read from `import { }`. 43 | // You can write arbitrary Nix expressions here, to produce valid "options" declaration result. 44 | // Tip: for flake-based configuration, utilize `builtins.getFlake` 45 | "nixos": { 46 | "expr": "(builtins.getFlake \"/absolute/path/to/flake\").nixosConfigurations..options", 47 | }, 48 | "home-manager": { 49 | "expr": "(builtins.getFlake \"/absolute/path/to/flake\").homeConfigurations..options", 50 | }, 51 | // Tip: use ${workspaceFolder} variable to define path 52 | "nix-darwin": { 53 | "expr": "(builtins.getFlake \"${workspaceFolder}/path/to/flake\").darwinConfigurations..options", 54 | }, 55 | }, 56 | } 57 | } 58 | } 59 | ``` 60 | 61 | ### Custom Formatter 62 | 63 | It can be changed by setting `nix.formatterPath` to any command which can accept file contents on stdin and return formatted text on stdout. 64 | 65 | > [!IMPORTANT] 66 | > If you are using the above LSP plugin setting, then this configuration is not used. 67 | 68 | ```json5 69 | { 70 | "nix.formatterPath": "nixfmt" // or "alejandra" 71 | // or pass full list of args like below 72 | // "nix.formatterPath": ["treefmt", "--stdin", "{file}"] 73 | } 74 | ``` 75 | 76 | ## Contributing 💪 77 | 78 | We welcome contributions to this extension. Kindly start with any of open issues or feature requests. 79 | 80 | See [CONTRIBUTING.md](./CONTRIBUTING.md) for more information. 81 | 82 | ## Credits 83 | 84 | Special thanks to: 85 | 86 | - [@wmertens](https://github.com/wmertens) for [writing the grammar](https://github.com/wmertens/sublime-nix/blob/master/nix.tmLanguage). 87 | - The [vscode-fish](https://github.com/bmalehorn/vscode-fish/) extension, which was modified to work for Nix in this extension. 88 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 3 | "vcs": { 4 | "enabled": true, 5 | "clientKind": "git", 6 | "useIgnoreFile": true 7 | }, 8 | "files": { 9 | "ignoreUnknown": false, 10 | "ignore": [] 11 | }, 12 | "formatter": { 13 | "enabled": true, 14 | "indentStyle": "space" 15 | }, 16 | "organizeImports": { 17 | "enabled": true 18 | }, 19 | "linter": { 20 | "enabled": true, 21 | "rules": { 22 | "recommended": true 23 | } 24 | }, 25 | "javascript": { 26 | "formatter": { 27 | "quoteStyle": "double" 28 | }, 29 | "globals": [ 30 | "exports" 31 | ] 32 | } 33 | } -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ["@commitlint/config-conventional"] }; 2 | -------------------------------------------------------------------------------- /images/docs/linting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nix-community/vscode-nix-ide/51da56019e246a5d96da64ccd8366473cc45637f/images/docs/linting.png -------------------------------------------------------------------------------- /images/docs/md-embed-nix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nix-community/vscode-nix-ide/51da56019e246a5d96da64ccd8366473cc45637f/images/docs/md-embed-nix.png -------------------------------------------------------------------------------- /images/docs/nix-syntax-highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nix-community/vscode-nix-ide/51da56019e246a5d96da64ccd8366473cc45637f/images/docs/nix-syntax-highlight.png -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nix-community/vscode-nix-ide/51da56019e246a5d96da64ccd8366473cc45637f/images/icon.png -------------------------------------------------------------------------------- /images/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /install.md: -------------------------------------------------------------------------------- 1 | ## Installation 🔨 2 | 3 | Available on both the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=jnoortheen.nix-ide) and the [Open VSX Registry](https://open-vsx.org/extension/jnoortheen/nix-ide). 4 | 5 | You can also open the Command Palette (Ctrl+Shift+P on Windows/Linux or Cmd+Shift+P on macOS) and enter `ext install jnoortheen.nix-ide` to install the extension, or download it from the [latest release](https://github.com/nix-community/vscode-nix-ide/releases/latest). 6 | -------------------------------------------------------------------------------- /language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "#", 5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 6 | "blockComment": [ 7 | "/*", 8 | "*/" 9 | ] 10 | }, 11 | // symbols used as brackets 12 | "brackets": [ 13 | [ 14 | "${", 15 | "}" 16 | ], 17 | [ 18 | "{", 19 | "}" 20 | ], 21 | [ 22 | "[", 23 | "]" 24 | ], 25 | [ 26 | "(", 27 | ")" 28 | ], 29 | [ 30 | "<", 31 | ">" 32 | ] 33 | ], 34 | // symbols that are auto closed when typing 35 | "autoClosingPairs": [ 36 | { 37 | "open": "{", 38 | "close": "}" 39 | }, 40 | { 41 | "open": "[", 42 | "close": "]" 43 | }, 44 | { 45 | "open": "(", 46 | "close": ")" 47 | }, 48 | { 49 | "open": "\"", 50 | "close": "\"", 51 | "notIn": [ 52 | "string" 53 | ] 54 | }, 55 | { 56 | "open": "''", 57 | "close": "''", 58 | "notIn": [ 59 | "string", 60 | "comment" 61 | ] 62 | }, 63 | { 64 | "open": "/**", 65 | "close": " */", 66 | "notIn": [ 67 | "string" 68 | ] 69 | } 70 | ], 71 | "autoCloseBefore": ";:.,=}])>` \n\t\"", 72 | // symbols that can be used to surround a selection 73 | "surroundingPairs": [ 74 | [ 75 | "{", 76 | "}" 77 | ], 78 | [ 79 | "[", 80 | "]" 81 | ], 82 | [ 83 | "(", 84 | ")" 85 | ], 86 | [ 87 | "<", 88 | ">" 89 | ], 90 | [ 91 | "\"", 92 | "\"" 93 | ], 94 | [ 95 | "'", 96 | "'" 97 | ], 98 | [ 99 | "''", 100 | "''" 101 | ], 102 | // Backticks don't have any special meaning in nix language, it's just for Markdown in comments. 103 | [ 104 | "`", 105 | "`" 106 | ], 107 | ], 108 | "folding": { 109 | "markers": { 110 | "start": "^\\s*#\\s*#?region\\b", 111 | "end": "^\\s*#\\s*#?endregion\\b" 112 | } 113 | }, 114 | "onEnterRules": [ 115 | { 116 | "beforeText": "^.*\\blet\\s*$", 117 | "afterText": "\\s*in\\b.*$", 118 | "action": { 119 | "indent": "indentOutdent" 120 | } 121 | }, 122 | { 123 | "beforeText": "^.*\\bif\\s*$", 124 | "afterText": "\\s*then\\b.*$", 125 | "action": { 126 | "indent": "indentOutdent" 127 | } 128 | }, 129 | { 130 | "beforeText": "^.*\\bthen\\s*$", 131 | "afterText": "\\s*else\\b.*$", 132 | "action": { 133 | "indent": "indentOutdent" 134 | } 135 | }, 136 | { 137 | "beforeText": "^.*''\\s*$", 138 | "afterText": "\\s*''.*$", 139 | "action": { 140 | "indent": "indentOutdent" 141 | } 142 | }, 143 | { 144 | "beforeText": "^.*/\\*\\*\\s*$", 145 | "afterText": "\\s*\\*/.*$", 146 | "action": { 147 | "indent": "indentOutdent" 148 | } 149 | }, 150 | { 151 | "beforeText": "^.*(?:=|/\\*\\*|'')\\s*$", 152 | "action": { 153 | "indent": "indent" 154 | } 155 | }, 156 | { 157 | // NOTE: `in` is not included on purpose, because nixfmt also doesn't indent after it. 158 | "beforeText": "^.*\\b(?:let|with|if|then|else|rec|or|and|assert|inherit)\\s*$", 159 | "action": { 160 | "indent": "indent" 161 | } 162 | }, 163 | ], 164 | "wordPattern": "(-?\\d*\\.\\d\\w*)|((~|[^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\<\\>\\/\\?\\s]+)/[^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\<\\>\\?\\s]+)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)" 165 | } 166 | -------------------------------------------------------------------------------- /lefthook.yml: -------------------------------------------------------------------------------- 1 | # EXAMPLE USAGE: 2 | # 3 | # Refer for explanation to following link: 4 | # https://evilmartians.github.io/lefthook/configuration/ 5 | 6 | pre-commit: 7 | parallel: true 8 | jobs: 9 | - run: bun run lint 10 | glob: "*.{js,ts,jsx,tsx}" 11 | 12 | commit-msg: 13 | jobs: 14 | - run: bun run commitlint --edit 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nix-ide", 3 | "displayName": "Nix IDE", 4 | "description": "Nix language support - syntax highlighting, formatting, and error reporting.", 5 | "version": "0.5.0", 6 | "publisher": "jnoortheen", 7 | "icon": "images/icon.png", 8 | "license": "MIT", 9 | "engines": { 10 | "vscode": ">=1.96.0" 11 | }, 12 | "categories": [ 13 | "Programming Languages", 14 | "Formatters", 15 | "Snippets" 16 | ], 17 | "keywords": [ 18 | "nix" 19 | ], 20 | "bugs": { 21 | "url": "https://github.com/nix-community/vscode-nix-ide/issues" 22 | }, 23 | "homepage": "https://github.com/nix-community/vscode-nix-ide", 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/nix-community/vscode-nix-ide" 27 | }, 28 | "main": "dist/extension.js", 29 | "contributes": { 30 | "languages": [ 31 | { 32 | "id": "nix", 33 | "aliases": [ 34 | "Nix", 35 | "nix" 36 | ], 37 | "extensions": [ 38 | ".nix" 39 | ], 40 | "icon": { 41 | "dark": "images/icon.svg", 42 | "light": "images/icon.svg" 43 | }, 44 | "configuration": "./language-configuration.json" 45 | } 46 | ], 47 | "grammars": [ 48 | { 49 | "language": "nix", 50 | "scopeName": "source.nix", 51 | "path": "./dist/nix.tmLanguage.json" 52 | }, 53 | { 54 | "scopeName": "markdown.nix.codeblock", 55 | "path": "./dist/injection.json", 56 | "injectTo": [ 57 | "text.html.markdown" 58 | ], 59 | "embeddedLanguages": { 60 | "meta.embedded.block.nix": "nix" 61 | } 62 | } 63 | ], 64 | "snippets": [ 65 | { 66 | "language": "nix", 67 | "path": "./snippets.json" 68 | } 69 | ], 70 | "configuration": { 71 | "title": "NixIDE", 72 | "properties": { 73 | "nix.formatterPath": { 74 | "default": "nixfmt", 75 | "markdownDescription": "Full path to the nix formatter executable. This setting won't take effect if `nix.enableLanguageServer` is enabled; if that's the case, you can instead set formatter via `nix.serverSettings` (see [README](https://github.com/nix-community/vscode-nix-ide#lsp-plugin-support) for examples)", 76 | "oneOf": [ 77 | { 78 | "type": "string", 79 | "enum": [ 80 | "nixfmt", 81 | "nix3-fmt", 82 | "alejandra", 83 | "treefmt", 84 | "nixpkgs-fmt" 85 | ], 86 | "markdownEnumDescriptions": [ 87 | "[nixfmt](https://github.com/NixOS/nixfmt) - The official formatter for the Nix language", 88 | "[nix3-fmt](https://nix.dev/manual/nix/2.17/command-ref/new-cli/nix3-fmt) - Use the flake configured formatter", 89 | "[alejandra](https://github.com/kamadorueda/alejandra) - The Uncompromising Nix Code Formatter", 90 | "[treefmt](https://github.com/numtide/treefmt-nix) - All in one formatter", 91 | "[nixpkgs-fmt](https://github.com/nix-community/nixpkgs-fmt) - Deprecated as it is no longer maintained" 92 | ] 93 | }, 94 | { 95 | "type": "array", 96 | "items": "string", 97 | "minItems": 1 98 | } 99 | ] 100 | }, 101 | "nix.serverPath": { 102 | "default": "nil", 103 | "description": "Location of the nix language server command.", 104 | "oneOf": [ 105 | { 106 | "type": "string" 107 | }, 108 | { 109 | "type": "array", 110 | "items": "string", 111 | "minItems": 1 112 | } 113 | ] 114 | }, 115 | "nix.enableLanguageServer": { 116 | "type": "boolean", 117 | "default": false, 118 | "description": "Use LSP instead of nix-instantiate and the formatter configured via `nix.formatterPath`." 119 | }, 120 | "nix.serverSettings": { 121 | "type": "object", 122 | "default": {}, 123 | "description": "Settings passed to the language server on configuration requests." 124 | }, 125 | "nix.hiddenLanguageServerErrors": { 126 | "type": "array", 127 | "items": { 128 | "type": "string" 129 | }, 130 | "default": [], 131 | "description": "Error notifications from the language server for these request types will be suppressed.", 132 | "examples": [ 133 | [ 134 | "textDocument/definition", 135 | "textDocument/documentSymbol" 136 | ] 137 | ] 138 | } 139 | } 140 | }, 141 | "configurationDefaults": { 142 | "[nix]": { 143 | "editor.insertSpaces": true, 144 | "editor.tabSize": 2 145 | }, 146 | "explorer.fileNesting.patterns": { 147 | "flake.nix": "flake.lock" 148 | }, 149 | "files.associations": { 150 | "flake.lock": "json" 151 | } 152 | }, 153 | "commands": [ 154 | { 155 | "title": "Restart Language Server", 156 | "category": "Nix IDE", 157 | "command": "nix-ide.restartLanguageServer" 158 | } 159 | ], 160 | "semanticTokenTypes": [ 161 | { 162 | "id": "boolean", 163 | "description": "Style for boolean literals", 164 | "superType": "keywords" 165 | }, 166 | { 167 | "id": "constant", 168 | "description": "Style for `builtins` constants" 169 | }, 170 | { 171 | "id": "path", 172 | "description": "Style for paths" 173 | }, 174 | { 175 | "id": "punctuations", 176 | "description": "Style for punctuations" 177 | } 178 | ], 179 | "semanticTokenModifiers": [ 180 | { 181 | "id": "builtin", 182 | "description": "Style for `builtins` variables and functions" 183 | }, 184 | { 185 | "id": "conditional", 186 | "description": "Style for conditional operators and keywords" 187 | }, 188 | { 189 | "id": "delimiter", 190 | "description": "Style for delimiter punctuations" 191 | }, 192 | { 193 | "id": "escape", 194 | "description": "Style for escape sequences in strings" 195 | }, 196 | { 197 | "id": "parenthesis", 198 | "description": "Style for parenthesis" 199 | }, 200 | { 201 | "id": "unresolved", 202 | "description": "Style for unresolved variables" 203 | }, 204 | { 205 | "id": "withAttribute", 206 | "description": "Style for attributes from `with`" 207 | } 208 | ], 209 | "semanticTokenScopes": [ 210 | { 211 | "language": "nix", 212 | "scopes": { 213 | "boolean": [ 214 | "constant.language.boolean.nix" 215 | ], 216 | "constant.builtin": [ 217 | "support.const.nix" 218 | ], 219 | "function.builtin": [ 220 | "support.function.nix" 221 | ], 222 | "struct.builtin": [ 223 | "support.const.nix" 224 | ], 225 | "path": [ 226 | "constant.other.path.nix" 227 | ], 228 | "string": [ 229 | "string.quoted.double.nix" 230 | ], 231 | "string.escape": [ 232 | "constant.character.escape.nix" 233 | ], 234 | "variable": [ 235 | "variable.other.nix" 236 | ], 237 | "variable.unresolved": [ 238 | "invalid.nix" 239 | ], 240 | "parameter": [ 241 | "variable.parameter.name.nix" 242 | ], 243 | "property": [ 244 | "entity.other.attribute-name.single.nix" 245 | ], 246 | "*.withAttribute": [ 247 | "markup.underline" 248 | ], 249 | "operator": [ 250 | "entity.name.operator.nix" 251 | ] 252 | } 253 | } 254 | ] 255 | }, 256 | "devDependencies": { 257 | "@commitlint/cli": "^20.1.0", 258 | "@commitlint/config-conventional": "^20.0.0", 259 | "@types/command-exists": "^1.2.3", 260 | "@types/node": "^24.0.3", 261 | "@types/vscode": "^1.96.0", 262 | "@vscode/vsce": "^3.5.0", 263 | "js-yaml": "^4.1.0", 264 | "lefthook": "^1.11.14", 265 | "ovsx": "^0.10.4", 266 | "@vscode/test-cli": "^0.0.11", 267 | "@vscode/test-electron": "^2.5.2", 268 | "vscode-tmgrammar-test": "^0.1.3", 269 | "typescript": "^5.8.3" 270 | }, 271 | "scripts": { 272 | "prebuild": "mkdir -p dist && js-yaml syntaxes/nix.YAML-tmLanguage > dist/nix.tmLanguage.json && js-yaml syntaxes/injection.yml > dist/injection.json", 273 | "build": "bun build src/extension.ts --outdir=dist --external=vscode --target=node --format=cjs", 274 | "postinstall": "lefthook install", 275 | "clean": "rm -rd dist", 276 | "prepackage": "rm -f *.vsix", 277 | "package": "bun run build --minify && bun run vsce package --no-dependencies", 278 | "publish:ovsx": "ovsx publish *.vsix --pat '$OVS_PAT'", 279 | "publish:vsce": "vsce publish", 280 | "publish": "bun run package && bun run publish:vsce && bun run publish:ovsx", 281 | "pretest": "bun run build --sourcemap && vscode-tmgrammar-snap 'syntaxes/tests/*.nix'", 282 | "test": "vscode-test", 283 | "lint": "bun x biome check --write src" 284 | }, 285 | "dependencies": { 286 | "command-exists": "^1.2.9", 287 | "vscode-languageclient": "^9.0.1", 288 | "vscode-variables": "^1.0.1" 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import { } }: 2 | pkgs.mkShell { 3 | buildInputs = with pkgs; [ 4 | nodejs 5 | esbuild 6 | bun 7 | ]; 8 | shellHook = '' 9 | bun install 10 | ''; 11 | } 12 | -------------------------------------------------------------------------------- /snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditional": { 3 | "prefix": ["if"], 4 | "body": ["if $1 then $2 else $0"], 5 | "description": "Conditional expression" 6 | }, 7 | "let": { 8 | "prefix": ["let"], 9 | "body": ["let $1;", "in $0"], 10 | "description": "Let expression" 11 | }, 12 | "rec": { 13 | "prefix": ["rec"], 14 | "body": ["rec { $1", "\t$0}"], 15 | "description": "Recursive Set" 16 | }, 17 | "with": { 18 | "prefix": ["with"], 19 | "body": ["with $1;$0"], 20 | "description": "With expression" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific files 2 | *.suo 3 | *.user 4 | *.userosscache 5 | *.sln.docstates 6 | # User-specific files (MonoDevelop/Xamarin Studio) 7 | *.userprefs 8 | # Build results 9 | [Dd]ebug/ 10 | [Dd]ebugPublic/ 11 | [Rr]elease/ 12 | [Rr]eleases/ 13 | x64/ 14 | x86/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | [Ll]og/ 19 | # Visual Studio 2015-2017 cache/options directory 20 | .vs/ 21 | # Uncomment if you have tasks that create the project's static files in wwwroot 22 | # wwwroot/ 23 | # MSTest test Results 24 | [Tt]est[Rr]esult*/ 25 | [Bb]uild[Ll]og.* 26 | # NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | # Build Results of an ATL Project 30 | [Dd]ebugPS/ 31 | [Rr]eleasePS/ 32 | dlldata.c 33 | # DNX 34 | project.lock.json 35 | project.fragment.lock.json 36 | artifacts/ 37 | *_i.c 38 | *_p.c 39 | *_i.h 40 | *.ilk 41 | *.meta 42 | *.obj 43 | *.pch 44 | *.pdb 45 | *.pgc 46 | *.pgd 47 | *.rsp 48 | *.sbr 49 | *.tlb 50 | *.tli 51 | *.tlh 52 | *.tmp 53 | *.tmp_proj 54 | *.log 55 | *.vspscc 56 | *.vssscc 57 | .builds 58 | *.pidb 59 | *.svclog 60 | *.scc 61 | # Chutzpah Test files 62 | _Chutzpah* 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opendb 68 | *.opensdf 69 | *.sdf 70 | *.cachefile 71 | *.VC.db 72 | *.VC.VC.opendb 73 | # Visual Studio profiler 74 | *.psess 75 | *.vsp 76 | *.vspx 77 | *.sap 78 | # TFS Local Workspace 79 | $tf/ 80 | # Guidance Automation Toolkit 81 | *.gpState 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | # JustCode is a .NET coding add-in 87 | .JustCode 88 | # TeamCity is a build add-in 89 | _TeamCity* 90 | # DotCover is a Code Coverage Tool 91 | *.dotCover 92 | # Visual Studio code coverage results 93 | *.coverage 94 | *.coveragexml 95 | # NCrunch 96 | _NCrunch_* 97 | .*crunch*.local.xml 98 | nCrunchTemp_* 99 | # MightyMoose 100 | *.mm.* 101 | AutoTest.Net/ 102 | # Web workbench (sass) 103 | .sass-cache/ 104 | # Installshield output folder 105 | [Ee]xpress/ 106 | # DocProject is a documentation generator add-in 107 | DocProject/buildhelp/ 108 | DocProject/Help/*.HxT 109 | DocProject/Help/*.HxC 110 | DocProject/Help/*.hhc 111 | DocProject/Help/*.hhk 112 | DocProject/Help/*.hhp 113 | DocProject/Help/Html2 114 | DocProject/Help/html 115 | # Click-Once directory 116 | publish/ 117 | # Publish Web Output 118 | *.[Pp]ublish.xml 119 | *.azurePubxml 120 | # TODO: Comment the next line if you want to checkin your web deploy settings 121 | # but database connection strings (with potential passwords) will be unencrypted 122 | *.pubxml 123 | *.publishproj 124 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 125 | # checkin your Azure Web App publish settings, but sensitive information contained 126 | # in these scripts will be unencrypted 127 | PublishScripts/ 128 | # NuGet Packages 129 | *.nupkg 130 | # The packages folder can be ignored because of Package Restore 131 | **/packages/* 132 | # except build/, which is used as an MSBuild target. 133 | !**/packages/build/ 134 | # Uncomment if necessary however generally it will be regenerated when needed 135 | #!**/packages/repositories.config 136 | # NuGet v3's project.json files produces more ignoreable files 137 | *.nuget.props 138 | *.nuget.targets 139 | # Microsoft Azure Build Output 140 | csx/ 141 | *.build.csdef 142 | # Microsoft Azure Emulator 143 | ecf/ 144 | rcf/ 145 | # Windows Store app package directories and files 146 | AppPackages/ 147 | BundleArtifacts/ 148 | Package.StoreAssociation.xml 149 | _pkginfo.txt 150 | # Visual Studio cache files 151 | # files ending in .cache can be ignored 152 | *.[Cc]ache 153 | # but keep track of directories ending in .cache 154 | !*.[Cc]ache/ 155 | # Others 156 | ClientBin/ 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.jfm 162 | *.pfx 163 | *.publishsettings 164 | node_modules/ 165 | orleans.codegen.cs 166 | # Since there are multiple workflows, uncomment next line to ignore bower_components 167 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 168 | #bower_components/ 169 | # RIA/Silverlight projects 170 | Generated_Code/ 171 | # Backup & report files from converting an old project file 172 | # to a newer Visual Studio version. Backup files are not needed, 173 | # because we have git 😉 174 | _UpgradeReport_Files/ 175 | Backup*/ 176 | UpgradeLog*.XML 177 | UpgradeLog*.htm 178 | # SQL Server files 179 | *.mdf 180 | *.ldf 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | # Microsoft Fakes 186 | FakesAssemblies/ 187 | # GhostDoc plugin setting file 188 | *.GhostDoc.xml 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | # Visual Studio 6 build log 192 | *.plg 193 | # Visual Studio 6 workspace options file 194 | *.opt 195 | # Visual Studio LightSwitch build output 196 | **/*.HTMLClient/GeneratedArtifacts 197 | **/*.DesktopClient/GeneratedArtifacts 198 | **/*.DesktopClient/ModelManifest.xml 199 | **/*.Server/GeneratedArtifacts 200 | **/*.Server/ModelManifest.xml 201 | _Pvt_Extensions 202 | # Paket dependency manager 203 | .paket/paket.exe 204 | paket-files/ 205 | # FAKE - F# Make 206 | .fake/ 207 | # JetBrains Rider 208 | .idea/ 209 | *.sln.iml 210 | # CodeRush 211 | .cr/ 212 | # Python Tools for Visual Studio (PTVS) 213 | __pycache__/ 214 | *.pyc 215 | # Cake - Uncomment if you are using it 216 | -------------------------------------------------------------------------------- /src/client.ts: -------------------------------------------------------------------------------- 1 | // from PR of https://github.com/nix-community/vscode-nix-ide/pull/16/ 2 | 3 | // biome-ignore lint/style/useNodejsImportProtocol: 4 | import { inspect } from "util"; 5 | import { sync as commandExistsSync } from "command-exists"; 6 | import { 7 | type Disposable, 8 | type ExtensionContext, 9 | Uri, 10 | env, 11 | window, 12 | workspace, 13 | } from "vscode"; 14 | import type { 15 | CancellationToken, 16 | ConfigurationParams, 17 | LSPArray, 18 | LanguageClientOptions, 19 | MessageSignature, 20 | } from "vscode-languageclient"; 21 | import { 22 | type Executable, 23 | LanguageClient, 24 | type ServerOptions, 25 | } from "vscode-languageclient/node"; 26 | import { type UriMessageItem, config } from "./configuration"; 27 | 28 | class Client extends LanguageClient { 29 | disposables: Disposable[] = []; 30 | 31 | override handleFailedRequest( 32 | type: MessageSignature, 33 | token: CancellationToken | undefined, 34 | error: unknown, 35 | defaultValue: T, 36 | showNotification?: boolean, 37 | ): T { 38 | if (config.hiddenErrorKinds.includes(type.method)) { 39 | this.outputChannel.appendLine( 40 | `Suppressing failed ${inspect(type.method)} notification`, 41 | ); 42 | return super.handleFailedRequest(type, token, error, defaultValue, false); 43 | } 44 | return super.handleFailedRequest( 45 | type, 46 | token, 47 | error, 48 | defaultValue, 49 | showNotification, 50 | ); 51 | } 52 | 53 | override dispose(timeout?: number): Promise { 54 | let timedOut = false; 55 | if (timeout) { 56 | setTimeout(() => { 57 | timedOut = true; 58 | }, timeout); 59 | } 60 | 61 | for (const disposable of this.disposables) { 62 | if (timedOut) { 63 | break; 64 | } 65 | disposable.dispose(); 66 | } 67 | 68 | return Promise.resolve(); 69 | } 70 | } 71 | 72 | let client: Client; 73 | 74 | export async function activate(context: ExtensionContext): Promise { 75 | if (!commandExistsSync(config.serverPath[0])) { 76 | const selection = await window.showErrorMessage( 77 | `Command ${config.serverPath} not found in $PATH`, 78 | { 79 | title: "Install language server", 80 | uri: Uri.parse( 81 | "https://github.com/nix-community/vscode-nix-ide?tab=readme-ov-file#language-servers", 82 | ), 83 | }, 84 | ); 85 | if (selection?.uri !== undefined) { 86 | await env.openExternal(selection?.uri); 87 | return; 88 | } 89 | } 90 | const serverExecutable: Executable = { 91 | command: config.serverPath[0], 92 | args: config.serverPath.slice(1) 93 | }; 94 | const serverOptions: ServerOptions = serverExecutable; 95 | 96 | const nixDocumentSelector: { scheme: string; language: string }[] = [ 97 | { scheme: "file", language: "nix" }, 98 | { scheme: "untitled", language: "nix" }, 99 | ]; 100 | 101 | const outputChannel = window.createOutputChannel("Nix"); 102 | const fileEvents = workspace.createFileSystemWatcher("**/*.nix"); 103 | 104 | const clientOptions: LanguageClientOptions = { 105 | documentSelector: nixDocumentSelector, 106 | synchronize: { 107 | fileEvents, 108 | configurationSection: [config.rootSection], 109 | }, 110 | outputChannel, 111 | middleware: { 112 | workspace: { 113 | configuration: (params: ConfigurationParams): LSPArray[] => { 114 | const items = params.items || []; 115 | const res: LSPArray = []; 116 | const settings = config.serverSettings; 117 | for (const item of items) { 118 | if (!item?.section) { 119 | continue; 120 | } 121 | const sectionSettings = settings[item.section as keyof typeof settings] 122 | if (!sectionSettings) { 123 | client.warn(`failed to find "${item.section}" in "nix.serverSettings"`) 124 | } 125 | res.push(sectionSettings ?? null); 126 | } 127 | // eslint-disable-next-line @typescript-eslint/no-unsafe-return 128 | return res; 129 | }, 130 | }, 131 | }, 132 | }; 133 | 134 | client = new Client("nix", "Nix", serverOptions, clientOptions); 135 | client.disposables.push(outputChannel, fileEvents); 136 | client.registerProposedFeatures(); 137 | await client.start(); 138 | 139 | context.subscriptions.push(client); 140 | } 141 | 142 | export async function deactivate(): Promise { 143 | if (client?.needsStop()) { 144 | await client.stop(); 145 | } 146 | await client.dispose(); 147 | } 148 | 149 | export async function restart(context: ExtensionContext): Promise { 150 | const restartingMsg = window.setStatusBarMessage( 151 | "$(loading~spin) Restarting Nix language server", 152 | ); 153 | 154 | try { 155 | await deactivate(); 156 | await activate(context); 157 | } catch (error) { 158 | client?.error("Failed to restart Nix language server", error, "force"); 159 | } finally { 160 | restartingMsg.dispose(); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/configuration.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type ConfigurationChangeEvent, 3 | type WorkspaceConfiguration, 4 | workspace, 5 | } from "vscode"; 6 | import type { LSPObject } from "vscode-languageclient"; 7 | 8 | import type { MessageItem, Uri } from "vscode"; 9 | import { transformConfigValueByVscodeVariables } from "./utils"; 10 | 11 | export interface UriMessageItem extends MessageItem { 12 | uri: Uri; 13 | } 14 | 15 | export class Config { 16 | readonly rootSection = "nix"; 17 | 18 | private get cfg(): WorkspaceConfiguration { 19 | return workspace.getConfiguration(this.rootSection); 20 | } 21 | 22 | private get( 23 | path: string, 24 | def_val: T, 25 | ): T { 26 | return transformConfigValueByVscodeVariables( 27 | this.cfg.get(path) ?? def_val, 28 | ); 29 | } 30 | 31 | get formatterPath(): Array { 32 | const path: Array | string = this.get("formatterPath", "nixfmt"); 33 | if (typeof path === "string") { 34 | switch (path) { 35 | case "nix3-fmt": 36 | return ["nix", "fmt", "--", "--"]; 37 | case "treefmt": 38 | return ["treefmt", "--stdin", "{file}"]; 39 | default: 40 | return [path]; 41 | } 42 | } 43 | return path; 44 | } 45 | 46 | get serverPath(): Array { 47 | const path: Array | string = this.get("serverPath", "nil"); 48 | if (typeof path === "string") { 49 | return [path]; 50 | } 51 | return path; 52 | } 53 | 54 | get LSPEnabled(): boolean { 55 | return this.get("enableLanguageServer", false); 56 | } 57 | 58 | get hiddenErrorKinds(): string[] { 59 | return this.get("hiddenLanguageServerErrors", []); 60 | } 61 | 62 | get serverSettings(): LSPObject { 63 | return this.get("serverSettings", {}); 64 | } 65 | 66 | requiresServerRestart(change: ConfigurationChangeEvent): boolean { 67 | // NOTE: this might be easier if all the settings were nested under 68 | // e.g. `"nix.languageServer" or something like that, to deduplicate keys 69 | return ( 70 | change.affectsConfiguration("nix.serverPath") || 71 | change.affectsConfiguration("nix.enableLanguageServer") 72 | ); 73 | } 74 | } 75 | export const config = new Config(); 76 | -------------------------------------------------------------------------------- /src/extension.test.ts: -------------------------------------------------------------------------------- 1 | import assert = require("node:assert"); 2 | 3 | import * as vscode from "vscode"; 4 | 5 | describe("The resources", () => { 6 | const extension = vscode.extensions.getExtension("jnoortheen.vscode-nix-ide"); 7 | if (!extension) { 8 | assert.fail("Extension not found"); 9 | } 10 | // const iconName = "images/icon.png"; 11 | 12 | // it("provides valid icon paths", async () => { 13 | 14 | // }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import type { ExtensionContext } from "vscode"; 3 | import * as client from "./client"; 4 | import { config } from "./configuration"; 5 | import { formattingProviders } from "./formatter"; 6 | import { startLinting } from "./linter"; 7 | 8 | /** 9 | * Activate this extension. 10 | * 11 | * If LSP is enabled 12 | * then support IDE features with {@link https://github.com/oxalica/nil|nil} 13 | * Else 14 | * Format with nixpkgs-format 15 | * validate with nix-instantiate 16 | * 17 | * @param context The context for this extension 18 | * @return A promise for the initialization 19 | */ 20 | export async function activate(context: ExtensionContext): Promise { 21 | if (config.LSPEnabled) { 22 | try { 23 | await client.activate(context); 24 | } catch (err) { 25 | console.error(err); 26 | } 27 | } else { 28 | await startLinting(context); 29 | const subs = [ 30 | vscode.languages.registerDocumentFormattingEditProvider, 31 | vscode.languages.registerDocumentRangeFormattingEditProvider, 32 | ].map((func) => func("nix", formattingProviders)); 33 | context.subscriptions.concat(subs); 34 | } 35 | 36 | context.subscriptions.push( 37 | vscode.commands.registerCommand( 38 | "nix-ide.restartLanguageServer", 39 | async () => { 40 | if (config.LSPEnabled) { 41 | await client.restart(context); 42 | } 43 | }, 44 | ), 45 | ); 46 | 47 | vscode.workspace.onDidChangeConfiguration(async (event) => { 48 | if (config.requiresServerRestart(event)) { 49 | const choice = await vscode.window.showWarningMessage( 50 | "Configuration change requires restarting the language server", 51 | "Restart", 52 | ); 53 | if (choice === "Restart") { 54 | await client.restart(context); 55 | } 56 | } 57 | }); 58 | } 59 | 60 | export async function deactivate(): Promise { 61 | await client.deactivate(); 62 | } 63 | -------------------------------------------------------------------------------- /src/formatter.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { 3 | type DocumentFormattingEditProvider, 4 | type DocumentRangeFormattingEditProvider, 5 | Range, 6 | type TextDocument, 7 | TextEdit, 8 | } from "vscode"; 9 | import { config } from "./configuration"; 10 | import { type IProcessResult, runInWorkspace } from "./process-runner"; 11 | 12 | const FORMATTER: Array = config.formatterPath; 13 | 14 | /** 15 | * Get text edits to format a range in a document. 16 | * 17 | * @param document The document whose text to format 18 | * @param range The range within the document to format 19 | * @return A promise with the list of edits 20 | */ 21 | const getFormatRangeEdits = async ( 22 | document: TextDocument, 23 | range?: Range, 24 | ): Promise> => { 25 | const actualRange = document.validateRange( 26 | range || new Range(0, 0, Number.MAX_VALUE, Number.MAX_VALUE), 27 | ); 28 | let result: IProcessResult; 29 | try { 30 | FORMATTER.forEach((elm, i) => { 31 | FORMATTER[i] = elm.replace("{file}", document.fileName); 32 | }); 33 | result = await runInWorkspace( 34 | vscode.workspace.getWorkspaceFolder(document.uri), 35 | FORMATTER, 36 | document.getText(actualRange), 37 | ); 38 | } catch (error) { 39 | if (error instanceof Error) { 40 | await vscode.window.showErrorMessage( 41 | `Failed to run ${FORMATTER.join(" ")}: ${error.message}`, 42 | ); 43 | } 44 | // Re-throw the error to make the promise fail 45 | throw error; 46 | } 47 | return result.exitCode === 0 48 | ? [TextEdit.replace(actualRange, result.stdout)] 49 | : []; 50 | }; 51 | 52 | /** 53 | * A type for all formatting providers. 54 | */ 55 | type FormattingProviders = DocumentFormattingEditProvider & 56 | DocumentRangeFormattingEditProvider; 57 | 58 | /** 59 | * Formatting providers 60 | */ 61 | export const formattingProviders: FormattingProviders = { 62 | provideDocumentFormattingEdits: (document, _, token) => 63 | getFormatRangeEdits(document).then((edits) => 64 | token.isCancellationRequested 65 | ? [] 66 | : // tslint:disable-next-line:readonly-array 67 | (edits as TextEdit[]), 68 | ), 69 | provideDocumentRangeFormattingEdits: (document, range, _, token) => 70 | getFormatRangeEdits(document, range).then((edits) => 71 | token.isCancellationRequested 72 | ? [] 73 | : // tslint:disable-next-line:readonly-array 74 | (edits as TextEdit[]), 75 | ), 76 | }; 77 | -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | declare module "vscode-variables" { 2 | export default function variables( 3 | string: string, 4 | recursive?: boolean, 5 | ): string; 6 | } 7 | -------------------------------------------------------------------------------- /src/linter.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { Diagnostic, type ExtensionContext, type TextDocument } from "vscode"; 3 | import { runInWorkspace } from "./process-runner"; 4 | 5 | /** 6 | * Whether a given document is saved to disk and in Nix language. 7 | * 8 | * @param document The document to check 9 | * @return Whether the document is a Nix document saved to disk 10 | */ 11 | const isSavedDocument = (document: TextDocument): boolean => 12 | !document.isDirty && 13 | 0 < 14 | vscode.languages.match( 15 | { 16 | language: "nix", 17 | scheme: "file", 18 | }, 19 | document, 20 | ); 21 | 22 | interface LintErrorType { 23 | msg: string; 24 | row: number; 25 | col: number; 26 | } 27 | 28 | /** 29 | * Exec pattern against the given text and return an array of all matches. 30 | * 31 | * @param text The output from nix-instantiate stderr 32 | * @return All matches of pattern in text. 33 | */ 34 | const getErrors = (text: string): ReadonlyArray => { 35 | const results = []; 36 | // matches both syntax error messages, like: 37 | // `error: syntax error, unexpected ']', expecting ';', at /home/foo/bar/shell.nix:19:3` 38 | // as well as symbol error messages, like 39 | // `error: undefined variable 'openjdk' at /home/foo/bar/shell.nix:14:5` 40 | const pattern = /^error: (.+) at .+:(\d+):(\d+)$/gm; 41 | // We need to loop through the regexp here, so a let is required 42 | let match = pattern.exec(text); 43 | while (match !== null) { 44 | results.push({ 45 | msg: match[1], 46 | row: Number.parseInt(match[2]), 47 | col: Number.parseInt(match[3]), 48 | }); 49 | match = pattern.exec(text); 50 | } 51 | return results; 52 | }; 53 | 54 | /** 55 | * Parse errors from output for a given document. 56 | * 57 | * @param document The document to whose contents errors refer 58 | * @param output The error output from shell. 59 | * @return An array of all diagnostics 60 | */ 61 | const shellOutputToDiagnostics = ( 62 | document: TextDocument, 63 | output: string, 64 | ): ReadonlyArray => { 65 | const diagnostics: Array = []; 66 | for (const err of getErrors(output)) { 67 | const range = document.validateRange( 68 | new vscode.Range(err.row - 1, err.col - 2, err.row - 1, err.col + 2), 69 | ); 70 | const diagnostic = new Diagnostic(range, err.msg); 71 | diagnostic.source = "nix"; 72 | diagnostics.push(diagnostic); 73 | } 74 | return diagnostics; 75 | }; 76 | 77 | /** 78 | * Start linting files. 79 | * 80 | * @param context The extension context 81 | */ 82 | export async function startLinting(context: ExtensionContext): Promise { 83 | const diagnostics = vscode.languages.createDiagnosticCollection("nix"); 84 | context.subscriptions.push(diagnostics); 85 | 86 | const lint = async (document: TextDocument) => { 87 | if (isSavedDocument(document)) { 88 | const workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri); 89 | let d: ReadonlyArray; 90 | try { 91 | const result = await runInWorkspace(workspaceFolder, [ 92 | "nix-instantiate", 93 | "--parse", 94 | document.fileName, 95 | ]); 96 | d = shellOutputToDiagnostics(document, result.stderr); 97 | } catch (error) { 98 | if (error instanceof Error) { 99 | await vscode.window.showErrorMessage(error.message); 100 | } 101 | diagnostics.delete(document.uri); 102 | return; 103 | } 104 | diagnostics.set(document.uri, d as Diagnostic[]); 105 | } 106 | }; 107 | 108 | vscode.workspace.onDidOpenTextDocument(lint, null, context.subscriptions); 109 | vscode.workspace.onDidSaveTextDocument(lint, null, context.subscriptions); 110 | for await (const textDocument of vscode.workspace.textDocuments) { 111 | await lint(textDocument); 112 | } 113 | // Remove diagnostics for closed files 114 | vscode.workspace.onDidCloseTextDocument( 115 | (d) => diagnostics.delete(d.uri), 116 | null, 117 | context.subscriptions, 118 | ); 119 | } 120 | -------------------------------------------------------------------------------- /src/process-runner.ts: -------------------------------------------------------------------------------- 1 | import { execFile } from "node:child_process"; 2 | import type { WorkspaceFolder } from "vscode"; 3 | 4 | /** 5 | * A system error, i.e. an error that results from a syscall. 6 | */ 7 | interface ISystemError extends Error { 8 | readonly errno: string; 9 | } 10 | 11 | /** 12 | * Whether an error is a system error. 13 | * 14 | * @param error The error to check 15 | */ 16 | const isSystemError = (error: Error): error is ISystemError => 17 | (error as ISystemError).errno !== undefined && 18 | typeof (error as ISystemError).errno === "string"; 19 | 20 | /** 21 | * A process error. 22 | * 23 | * A process error occurs when the process exited with a non-zero exit code. 24 | */ 25 | interface IProcessError extends Error { 26 | /** 27 | * The exit code of the process. 28 | */ 29 | readonly code: number; 30 | } 31 | 32 | /** 33 | * Whether an error is a process error. 34 | */ 35 | const isProcessError = (error: Error): error is IProcessError => 36 | !isSystemError(error) && 37 | (error as IProcessError).code !== undefined && 38 | (error as IProcessError).code > 0; 39 | 40 | /** 41 | * The result of a process. 42 | */ 43 | export interface IProcessResult { 44 | /** 45 | * The integral exit code. 46 | */ 47 | readonly exitCode: number; 48 | /** 49 | * The standard output. 50 | */ 51 | readonly stdout: string; 52 | /** 53 | * The standard error. 54 | */ 55 | readonly stderr: string; 56 | } 57 | 58 | /** 59 | * Run a command in a given workspace folder. 60 | * 61 | * If the workspace folder is undefined run the command in the working directory 62 | * if the vscode instance. 63 | * 64 | * @param folder The folder to run the command in 65 | * @param command The command array 66 | * @param stdin An optional string to feed to standard input 67 | * @return The result of the process as promise 68 | */ 69 | export const runInWorkspace = ( 70 | folder: WorkspaceFolder | undefined, 71 | command: ReadonlyArray, 72 | stdin?: string, 73 | ): Promise => 74 | new Promise((resolve, reject) => { 75 | const cwd = folder ? folder.uri.fsPath : process.cwd(); 76 | const child = execFile( 77 | command[0], 78 | command.slice(1), 79 | { cwd }, 80 | (error, stdout, stderr) => { 81 | if (error && !isProcessError(error)) { 82 | // Throw system errors, but do not fail if the command 83 | // fails with a non-zero exit code. 84 | console.error("Command error", command, error); 85 | reject(error); // eslint-disable-line @typescript-eslint/prefer-promise-reject-errors 86 | } else { 87 | const exitCode = error ? error.code : 0; 88 | resolve({ stdout, stderr, exitCode }); 89 | } 90 | }, 91 | ); 92 | if (stdin && child.stdin) { 93 | child.stdin.end(stdin); 94 | } 95 | }); 96 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { LSPObject } from "vscode-languageclient"; 2 | import variables from "vscode-variables"; 3 | 4 | /** 5 | * transform config value by vscode variables 6 | * @link https://www.npmjs.com/package/vscode-variables?activeTab=readme 7 | */ 8 | export const transformConfigValueByVscodeVariables = < 9 | T extends string | boolean | LSPObject, 10 | >( 11 | _cfg: T, 12 | ): T => { 13 | let cfg = _cfg; 14 | try { 15 | if (typeof cfg === "string") { 16 | cfg = variables(cfg) as T; 17 | } else if (!!cfg && typeof cfg === "object") { 18 | for (const key of Object.keys(cfg)) { 19 | cfg[key] = transformConfigValueByVscodeVariables(cfg[key]); 20 | } 21 | } else if (Array.isArray(cfg) && cfg.length > 0) { 22 | cfg = cfg.map( 23 | (item) => transformConfigValueByVscodeVariables(item) as unknown, 24 | ) as T; 25 | } 26 | return cfg; 27 | } catch (err) { 28 | console.error(err); 29 | return cfg; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /syntaxes/.gitignore: -------------------------------------------------------------------------------- 1 | *.json -------------------------------------------------------------------------------- /syntaxes/injection.yml: -------------------------------------------------------------------------------- 1 | --- 2 | fileTypes: [] 3 | injectionSelector: L:text.html.markdown 4 | patterns: 5 | - include: "#nix-code-block" 6 | repository: 7 | nix-code-block: 8 | begin: "(^|\\G)(\\s*)(\\`{3,}|~{3,})\\s*(?i:(nix)(\\s+[^`~]*)?$)" 9 | name: markup.fenced_code.block.markdown 10 | end: "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$" 11 | beginCaptures: 12 | "3": 13 | name: punctuation.definition.markdown 14 | "5": 15 | name: fenced_code.block.language 16 | "6": 17 | name: fenced_code.block.language.attributes 18 | endCaptures: 19 | "3": 20 | name: punctuation.definition.markdown 21 | patterns: 22 | - begin: "(^|\\G)(\\s*)(.*)" 23 | while: "(^|\\G)(?!\\s*([`~]{3,})\\s*$)" 24 | contentName: meta.embedded.block.nix 25 | patterns: 26 | - include: source.nix 27 | scopeName: markdown.nix.codeblock 28 | -------------------------------------------------------------------------------- /syntaxes/nix.YAML-tmLanguage: -------------------------------------------------------------------------------- 1 | # [PackageDev] target_format: plist, ext: tmLanguage 2 | # Made by Wout.Mertens@gmail.com 3 | # 4 | # This grammar tries to be complete, but regex-based highlighters 5 | # can't be full parsers. Therefore it's a bit looser than the Nix 6 | # parser itself and some legal constructs will be marked as illegal. 7 | # It seems to work fine for nixpkgs. 8 | # 9 | # 10 | # While reading this, bear in mind that multi-line matches are not 11 | # allowed and the end regex is tested before enclosed patterns regexes 12 | # However, you can look-ahead to an end pattern with (?=...), which allows 13 | # you to match everything in a block 14 | # 15 | # 16 | # To enforce multipart expressions, a wrapper pattern is used 17 | # that matches the beginning and end with look-ahead. 18 | # Then the parts are chained with look-aheads. 19 | # 20 | # Unfortunately this doesn't work if the end condition matches 21 | # the end of a part, in that case the part is fully matched 22 | # instead of with a look-ahead 23 | # and legal expressions should still match properly. 24 | # 25 | # Known issues: 26 | # - attrset: 27 | # - if the closing brace of an empty { } block is at column 1 28 | # of the line, it will terminate the expression and mark 29 | # expression-cont rules as invalid 30 | # 31 | # There are no named regexes, so here's a list for copy-paste: 32 | # identifier: [a-zA-Z\_][a-zA-Z0-9\_\'\-]* 33 | # expression terminator next: (?=([\])};,]|\b(else|then)\b)) 34 | # match anything coming next: (?=.?) 35 | # match until end of file: $^ 36 | 37 | --- 38 | name: Nix 39 | scopeName: source.nix 40 | fileTypes: ["nix"] 41 | uuid: 0514fd5f-acb6-436d-b42c-7643e6d36c8f 42 | 43 | patterns: 44 | - include: "#expression" 45 | 46 | repository: 47 | expression: 48 | patterns: 49 | - include: "#parens-and-cont" 50 | - include: "#list-and-cont" 51 | - include: "#string" 52 | - include: "#interpolation" 53 | - include: "#with-assert" 54 | - include: "#function-for-sure" 55 | - include: "#attrset-for-sure" 56 | - include: "#attrset-or-function" 57 | - include: "#let" 58 | - include: "#if" 59 | - include: "#operator-unary" 60 | - include: "#constants" 61 | - include: "#bad-reserved" 62 | - include: "#parameter-name-and-cont" 63 | - include: "#others" 64 | expression-cont: 65 | begin: (?=.?) 66 | end: (?=([\])};,]|\b(else|then)\b)) 67 | patterns: 68 | - include: "#parens" 69 | - include: "#list" 70 | - include: "#string" 71 | - include: "#interpolation" 72 | - include: "#function-for-sure" 73 | - include: "#attrset-for-sure" 74 | - include: "#attrset-or-function" 75 | - name: keyword.operator.nix 76 | match: (\bor\b|\.|\|\>|\<\||==|!=|!|\<\=|\<|\>\=|\>|&&|\|\||-\>|//|\?|\+\+|-|\*|/(?=([^*]|$))|\+) 77 | - include: "#constants" 78 | - include: "#bad-reserved" 79 | - include: "#parameter-name" 80 | - include: "#others" 81 | 82 | parens: 83 | begin: \( 84 | beginCaptures: 85 | "0": { name: punctuation.definition.expression.nix } 86 | end: \) 87 | endCaptures: 88 | "0": { name: punctuation.definition.expression.nix } 89 | patterns: 90 | - include: "#expression" 91 | parens-and-cont: 92 | begin: (?=\() 93 | end: (?=([\])};,]|\b(else|then)\b)) 94 | patterns: 95 | - include: "#parens" 96 | - include: "#expression-cont" 97 | 98 | list: 99 | begin: \[ 100 | beginCaptures: 101 | "0": { name: punctuation.definition.list.nix } 102 | end: \] 103 | endCaptures: 104 | "0": { name: punctuation.definition.list.nix } 105 | patterns: 106 | - include: "#expression" 107 | list-and-cont: 108 | begin: (?=\[) 109 | end: (?=([\])};,]|\b(else|then)\b)) 110 | patterns: 111 | - include: "#list" 112 | - include: "#expression-cont" 113 | 114 | attrset-for-sure: 115 | patterns: 116 | - begin: (?=\brec\b) 117 | end: (?=([\])};,]|\b(else|then)\b)) 118 | patterns: 119 | - begin: \brec\b 120 | end: (?=\{) 121 | beginCaptures: 122 | "0": { name: keyword.other.nix } 123 | patterns: 124 | - include: "#others" 125 | - include: "#attrset-definition" 126 | - include: "#others" 127 | - begin: (?=\{\s*(\}|[^,?]*(=|;))) 128 | end: (?=([\])};,]|\b(else|then)\b)) 129 | patterns: 130 | - include: "#attrset-definition" 131 | - include: "#others" 132 | 133 | attrset-definition: 134 | begin: (?=\{) 135 | end: (?=([\])};,]|\b(else|then)\b)) 136 | patterns: 137 | - begin: (\{) 138 | end: (\}) 139 | beginCaptures: { "0": { name: punctuation.definition.attrset.nix } } 140 | endCaptures: { "0": { name: punctuation.definition.attrset.nix } } 141 | patterns: 142 | - include: "#attrset-contents" 143 | - begin: (?<=\}) 144 | end: (?=([\])};,]|\b(else|then)\b)) 145 | patterns: 146 | - include: "#expression-cont" 147 | attrset-definition-brace-opened: 148 | patterns: 149 | - begin: (?<=\}) 150 | end: (?=([\])};,]|\b(else|then)\b)) 151 | patterns: 152 | - include: "#expression-cont" 153 | - begin: (?=.?) 154 | end: \} 155 | endCaptures: { "0": { name: punctuation.definition.attrset.nix } } 156 | patterns: 157 | - include: "#attrset-contents" 158 | 159 | attrset-contents: 160 | patterns: 161 | - include: "#attribute-inherit" 162 | - include: "#bad-reserved" 163 | - include: "#attribute-bind" 164 | - include: "#others" 165 | 166 | function-header-open-brace: 167 | begin: \{ 168 | end: (?=\}) 169 | beginCaptures: 170 | "0": { name: punctuation.definition.entity.function.2.nix } 171 | patterns: 172 | - include: "#function-contents" 173 | function-header-close-brace-no-arg: 174 | begin: \} 175 | end: (?=\:) 176 | beginCaptures: 177 | "0": { name: punctuation.definition.entity.function.nix } 178 | patterns: 179 | - include: "#others" 180 | function-header-terminal-arg: 181 | begin: (?=@) 182 | end: (?=\:) 183 | patterns: 184 | - begin: \@ 185 | end: (?=\:) 186 | patterns: 187 | - begin: (\b[a-zA-Z\_][a-zA-Z0-9\_\'\-]*) 188 | end: (?=\:) 189 | name: variable.parameter.function.3.nix 190 | - include: "#others" 191 | - include: "#others" 192 | function-header-close-brace-with-arg: 193 | begin: \} 194 | end: (?=\:) 195 | beginCaptures: 196 | "0": { name: punctuation.definition.entity.function.nix } 197 | patterns: 198 | - include: "#function-header-terminal-arg" 199 | - include: "#others" 200 | function-header-until-colon-no-arg: 201 | begin: (?=\{) 202 | end: (?=\:) 203 | patterns: 204 | - include: "#function-header-open-brace" 205 | - include: "#function-header-close-brace-no-arg" 206 | function-header-until-colon-with-arg: 207 | begin: (?=\{) 208 | end: (?=\:) 209 | patterns: 210 | - include: "#function-header-open-brace" 211 | - include: "#function-header-close-brace-with-arg" 212 | function-body-from-colon: 213 | begin: (\:) 214 | end: (?=([\])};,]|\b(else|then)\b)) 215 | beginCaptures: 216 | "0": { name: punctuation.definition.function.nix } 217 | patterns: 218 | - include: "#expression" 219 | function-definition: 220 | begin: (?=.?) 221 | end: (?=([\])};,]|\b(else|then)\b)) 222 | patterns: 223 | - include: "#function-body-from-colon" 224 | # Chained expressions for [arg@]{a,b,c?xxx}[@arg]:yyy 225 | - begin: (?=.?) 226 | end: (?=\:) 227 | patterns: 228 | # arg @ { ... 229 | - begin: (\b[a-zA-Z\_][a-zA-Z0-9\_\'\-]*) 230 | end: (?=\:) 231 | beginCaptures: 232 | "0": { name: variable.parameter.function.4.nix } 233 | patterns: 234 | - begin: \@ 235 | end: (?=\:) 236 | patterns: 237 | - include: "#function-header-until-colon-no-arg" 238 | - include: "#others" 239 | - include: "#others" 240 | # { ... 241 | - begin: (?=\{) 242 | end: (?=\:) 243 | patterns: 244 | - include: "#function-header-until-colon-with-arg" 245 | - include: "#others" 246 | function-definition-brace-opened: 247 | begin: (?=.?) 248 | end: (?=([\])};,]|\b(else|then)\b)) 249 | patterns: 250 | - include: "#function-body-from-colon" 251 | # Chained expressions for a,b,c?xxx}[@arg]:yyy 252 | - begin: (?=.?) 253 | end: (?=\:) 254 | patterns: 255 | - include: "#function-header-close-brace-with-arg" 256 | - begin: (?=.?) 257 | end: (?=\}) 258 | patterns: 259 | - include: "#function-contents" 260 | - include: "#others" 261 | 262 | function-for-sure: 263 | patterns: 264 | # x: ... | {stuff}: ... | {a, b ? c, ... | arg @ {... 265 | # Patch: Exclude double and single quotes from function param match to avoid matching }: inside strings 266 | - begin: (?=(\b[a-zA-Z\_][a-zA-Z0-9\_\'\-]*\s*[:@]|\{[^}\"']*\}\s*:|\{[^#}"'/=]*[,\?])) 267 | end: (?=([\])};,]|\b(else|then)\b)) 268 | patterns: 269 | - include: "#function-definition" 270 | 271 | function-contents: 272 | patterns: 273 | - include: "#bad-reserved" 274 | - include: "#function-parameter" 275 | - include: "#others" 276 | 277 | attrset-or-function: 278 | begin: \{ 279 | beginCaptures: 280 | "0": { name: punctuation.definition.attrset-or-function.nix } 281 | # Note the absence of a comma here, otherwise comma-first fails 282 | end: (?=([\])};]|\b(else|then)\b)) 283 | patterns: 284 | # We have no clue what to expect so we allow both until we hit one 285 | # attrset contents => treat the rest as attrset 286 | - begin: (?=(\s*\}|\"|\binherit\b|\$\{|\b[a-zA-Z\_][a-zA-Z0-9\_\'\-]*(\s*\.|\s*=[^=]))) 287 | end: (?=([\])};,]|\b(else|then)\b)) 288 | patterns: 289 | - include: "#attrset-definition-brace-opened" 290 | # function contents => treat the rest as function header 291 | - begin: (?=(\.\.\.|\b[a-zA-Z\_][a-zA-Z0-9\_\'\-]*\s*[,?])) 292 | end: (?=([\])};,]|\b(else|then)\b)) 293 | patterns: 294 | - include: "#function-definition-brace-opened" 295 | # this line has no hints, eat the first word of the set 296 | - include: "#bad-reserved" 297 | - begin: \b[a-zA-Z\_][a-zA-Z0-9\_\'\-]* 298 | # Note the absence of a comma here, otherwise comma-first fails 299 | end: (?=([\])};]|\b(else|then)\b)) 300 | # unmatched first word is likely a function call 301 | beginCaptures: { "0": { name: variable.parameter.function.maybe.nix } } 302 | patterns: 303 | - begin: (?=\.) 304 | end: (?=([\])};,]|\b(else|then)\b)) 305 | patterns: 306 | - include: "#attrset-definition-brace-opened" 307 | # Note the \s*, this matches before the end-of-expr matches except at beginning 308 | - begin: \s*(\,) 309 | beginCaptures: { "1": { name: keyword.operator.nix } } 310 | end: (?=([\])};,]|\b(else|then)\b)) 311 | patterns: 312 | - include: "#function-definition-brace-opened" 313 | - begin: (?=\=) 314 | end: (?=([\])};,]|\b(else|then)\b)) 315 | patterns: 316 | - include: "#attribute-bind-from-equals" 317 | - include: "#attrset-definition-brace-opened" 318 | - begin: (?=\?) 319 | end: (?=([\])};,]|\b(else|then)\b)) 320 | patterns: 321 | - include: "#function-parameter-default" 322 | - begin: \, 323 | beginCaptures: 324 | "0": { name: keyword.operator.nix } 325 | end: (?=([\])};,]|\b(else|then)\b)) 326 | patterns: 327 | - include: "#function-definition-brace-opened" 328 | - include: "#others" 329 | - include: "#others" 330 | 331 | with-assert: 332 | begin: (?) 459 | beginCaptures: { "0": { name: string.unquoted.spath.nix } } 460 | end: (?=([\])};,]|\b(else|then)\b)) 461 | patterns: 462 | - include: "#expression-cont" 463 | - begin: ([a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+) 464 | beginCaptures: { "0": { name: string.unquoted.url.nix } } 465 | end: (?=([\])};,]|\b(else|then)\b)) 466 | patterns: 467 | - include: "#expression-cont" 468 | 469 | parameter-name: 470 | match: \b[a-zA-Z\_][a-zA-Z0-9\_\'\-]* 471 | captures: { "0": { name: variable.parameter.name.nix } } 472 | 473 | parameter-name-and-cont: 474 | begin: \b[a-zA-Z\_][a-zA-Z0-9\_\'\-]* 475 | end: (?=([\])};,]|\b(else|then)\b)) 476 | beginCaptures: { "0": { name: variable.parameter.name.nix } } 477 | patterns: 478 | - include: "#expression-cont" 479 | 480 | attribute-name-single: 481 | match: \b[a-zA-Z\_][a-zA-Z0-9\_\'\-]* 482 | name: entity.other.attribute-name.single.nix 483 | 484 | attribute-name: 485 | # Unfortunately, no pattern ordering can be enforced. Ah well. 486 | patterns: 487 | - match: \b[a-zA-Z\_][a-zA-Z0-9\_\'\-]* 488 | name: entity.other.attribute-name.multipart.nix 489 | - match: \. 490 | - include: "#string-quoted" 491 | - include: "#interpolation" 492 | 493 | function-parameter-default: 494 | begin: \? 495 | beginCaptures: 496 | "0": { name: keyword.operator.nix } 497 | end: (?=[,}]) 498 | patterns: 499 | - include: "#expression" 500 | function-parameter: 501 | patterns: 502 | - begin: (\.\.\.) 503 | end: (,|(?=\})) 504 | name: keyword.operator.nix 505 | patterns: 506 | - include: "#others" 507 | - begin: \b[a-zA-Z\_][a-zA-Z0-9\_\'\-]* 508 | beginCaptures: 509 | "0": { name: variable.parameter.function.1.nix } 510 | end: (,|(?=\})) 511 | endCaptures: 512 | "0": { name: keyword.operator.nix } 513 | patterns: 514 | - include: "#whitespace" 515 | - include: "#comment" 516 | - include: "#function-parameter-default" 517 | - include: "#expression" 518 | - include: "#others" 519 | 520 | attribute-inherit: 521 | begin: \binherit\b 522 | beginCaptures: { "0": { name: keyword.other.inherit.nix } } 523 | end: \; 524 | endCaptures: { "0": { name: punctuation.terminator.inherit.nix } } 525 | patterns: 526 | # This should only match once, in front. Ah well. 527 | - begin: \( 528 | end: (?=\;) 529 | beginCaptures: 530 | { "0": { name: punctuation.section.function.arguments.nix } } 531 | patterns: 532 | - begin: \) 533 | end: (?=\;) 534 | beginCaptures: 535 | { "0": { name: punctuation.section.function.arguments.nix } } 536 | patterns: 537 | - include: "#bad-reserved" 538 | - include: "#attribute-name-single" 539 | - include: "#others" 540 | - include: "#expression" 541 | - begin: (?=[a-zA-Z\_]) 542 | end: (?=\;) 543 | patterns: 544 | - include: "#bad-reserved" 545 | - include: "#attribute-name-single" 546 | - include: "#others" 547 | - include: "#others" 548 | 549 | attribute-bind-from-equals: 550 | begin: \= 551 | beginCaptures: 552 | "0": { name: keyword.operator.bind.nix } 553 | end: \; 554 | endCaptures: 555 | "0": { name: punctuation.terminator.bind.nix } 556 | patterns: 557 | - include: "#expression" 558 | attribute-bind: 559 | patterns: 560 | - include: "#attribute-name" 561 | # Wish this could match only after an attribute. Ah well. 562 | - include: "#attribute-bind-from-equals" 563 | 564 | operator-unary: 565 | name: keyword.operator.unary.nix 566 | match: (!|-) 567 | 568 | constants: 569 | patterns: 570 | - begin: \b(builtins|true|false|null)\b 571 | end: (?=([\])};,]|\b(else|then)\b)) 572 | beginCaptures: 573 | "0": { name: constant.language.nix } 574 | patterns: 575 | - include: "#expression-cont" 576 | - beginCaptures: { "0": { name: support.function.nix } } 577 | begin: \b(scopedImport|import|isNull|abort|throw|baseNameOf|dirOf|removeAttrs|map|toString|derivationStrict|derivation)\b 578 | end: (?=([\])};,]|\b(else|then)\b)) 579 | patterns: 580 | - include: "#expression-cont" 581 | - beginCaptures: { "0": { name: constant.numeric.nix } } 582 | begin: \b[0-9]+\b 583 | end: (?=([\])};,]|\b(else|then)\b)) 584 | patterns: 585 | - include: "#expression-cont" 586 | 587 | whitespace: 588 | match: \s+ 589 | 590 | illegal: 591 | match: . 592 | name: invalid.illegal 593 | 594 | others: 595 | patterns: 596 | - include: "#whitespace" 597 | - include: "#comment" 598 | - include: "#illegal" 599 | 600 | bad-reserved: 601 | # we don't mark "or" because it's a special case 602 | match: (? 1 then "a" else "b"); 4 | case_2 = (if 2 < 1 then "a" else "b"); 5 | case_3 = (if 2 >= 1 then "a" else "b"); 6 | case_4 = (if 2 <= 1 then "a" else "b"); 7 | case_5 = (true -> true); # (implication operator) 8 | } -------------------------------------------------------------------------------- /syntaxes/tests/bug-508.nix.snap: -------------------------------------------------------------------------------- 1 | ># from https://github.com/nix-community/vscode-nix-ide/issues/508 2 | #^ source.nix comment.line.number-sign.nix 3 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.nix comment.line.number-sign.nix 4 | >{ 5 | #^ source.nix punctuation.definition.attrset-or-function.nix 6 | > case_1 = (if 2 > 1 then "a" else "b"); 7 | #^^ source.nix 8 | # ^^^^^^ source.nix entity.other.attribute-name.multipart.nix 9 | # ^ source.nix 10 | # ^ source.nix keyword.operator.bind.nix 11 | # ^ source.nix 12 | # ^ source.nix punctuation.definition.expression.nix 13 | # ^^ source.nix keyword.other.nix 14 | # ^ source.nix 15 | # ^ source.nix constant.numeric.nix 16 | # ^ source.nix 17 | # ^ source.nix keyword.operator.nix 18 | # ^ source.nix 19 | # ^ source.nix constant.numeric.nix 20 | # ^ source.nix 21 | # ^^ source.nix keyword.other.nix 22 | # ^^ source.nix keyword.other.nix 23 | # ^ source.nix 24 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 25 | # ^ source.nix string.quoted.double.nix 26 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 27 | # ^ source.nix 28 | # ^^ source.nix keyword.other.nix 29 | # ^^ source.nix keyword.other.nix 30 | # ^ source.nix 31 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 32 | # ^ source.nix string.quoted.double.nix 33 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 34 | # ^ source.nix punctuation.definition.expression.nix 35 | # ^ source.nix punctuation.terminator.bind.nix 36 | > case_2 = (if 2 < 1 then "a" else "b"); 37 | #^^ source.nix 38 | # ^^^^^^ source.nix entity.other.attribute-name.multipart.nix 39 | # ^ source.nix 40 | # ^ source.nix keyword.operator.bind.nix 41 | # ^ source.nix 42 | # ^ source.nix punctuation.definition.expression.nix 43 | # ^^ source.nix keyword.other.nix 44 | # ^ source.nix 45 | # ^ source.nix constant.numeric.nix 46 | # ^ source.nix 47 | # ^ source.nix keyword.operator.nix 48 | # ^ source.nix 49 | # ^ source.nix constant.numeric.nix 50 | # ^ source.nix 51 | # ^^ source.nix keyword.other.nix 52 | # ^^ source.nix keyword.other.nix 53 | # ^ source.nix 54 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 55 | # ^ source.nix string.quoted.double.nix 56 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 57 | # ^ source.nix 58 | # ^^ source.nix keyword.other.nix 59 | # ^^ source.nix keyword.other.nix 60 | # ^ source.nix 61 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 62 | # ^ source.nix string.quoted.double.nix 63 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 64 | # ^ source.nix punctuation.definition.expression.nix 65 | # ^ source.nix punctuation.terminator.bind.nix 66 | > case_3 = (if 2 >= 1 then "a" else "b"); 67 | #^^ source.nix 68 | # ^^^^^^ source.nix entity.other.attribute-name.multipart.nix 69 | # ^ source.nix 70 | # ^ source.nix keyword.operator.bind.nix 71 | # ^ source.nix 72 | # ^ source.nix punctuation.definition.expression.nix 73 | # ^^ source.nix keyword.other.nix 74 | # ^ source.nix 75 | # ^ source.nix constant.numeric.nix 76 | # ^ source.nix 77 | # ^^ source.nix keyword.operator.nix 78 | # ^ source.nix 79 | # ^ source.nix constant.numeric.nix 80 | # ^ source.nix 81 | # ^^ source.nix keyword.other.nix 82 | # ^^ source.nix keyword.other.nix 83 | # ^ source.nix 84 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 85 | # ^ source.nix string.quoted.double.nix 86 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 87 | # ^ source.nix 88 | # ^^ source.nix keyword.other.nix 89 | # ^^ source.nix keyword.other.nix 90 | # ^ source.nix 91 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 92 | # ^ source.nix string.quoted.double.nix 93 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 94 | # ^ source.nix punctuation.definition.expression.nix 95 | # ^ source.nix punctuation.terminator.bind.nix 96 | > case_4 = (if 2 <= 1 then "a" else "b"); 97 | #^^ source.nix 98 | # ^^^^^^ source.nix entity.other.attribute-name.multipart.nix 99 | # ^ source.nix 100 | # ^ source.nix keyword.operator.bind.nix 101 | # ^ source.nix 102 | # ^ source.nix punctuation.definition.expression.nix 103 | # ^^ source.nix keyword.other.nix 104 | # ^ source.nix 105 | # ^ source.nix constant.numeric.nix 106 | # ^ source.nix 107 | # ^^ source.nix keyword.operator.nix 108 | # ^ source.nix 109 | # ^ source.nix constant.numeric.nix 110 | # ^ source.nix 111 | # ^^ source.nix keyword.other.nix 112 | # ^^ source.nix keyword.other.nix 113 | # ^ source.nix 114 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 115 | # ^ source.nix string.quoted.double.nix 116 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 117 | # ^ source.nix 118 | # ^^ source.nix keyword.other.nix 119 | # ^^ source.nix keyword.other.nix 120 | # ^ source.nix 121 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 122 | # ^ source.nix string.quoted.double.nix 123 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 124 | # ^ source.nix punctuation.definition.expression.nix 125 | # ^ source.nix punctuation.terminator.bind.nix 126 | > case_5 = (true -> true); # (implication operator) 127 | #^^ source.nix 128 | # ^^^^^^ source.nix entity.other.attribute-name.multipart.nix 129 | # ^ source.nix 130 | # ^ source.nix keyword.operator.bind.nix 131 | # ^ source.nix 132 | # ^ source.nix punctuation.definition.expression.nix 133 | # ^^^^ source.nix constant.language.nix 134 | # ^ source.nix 135 | # ^^ source.nix keyword.operator.nix 136 | # ^ source.nix 137 | # ^^^^ source.nix constant.language.nix 138 | # ^ source.nix punctuation.definition.expression.nix 139 | # ^ source.nix punctuation.terminator.bind.nix 140 | # ^ source.nix 141 | # ^ source.nix comment.line.number-sign.nix 142 | # ^^^^^^^^^^^^^^^^^^^^^^^ source.nix comment.line.number-sign.nix 143 | >} 144 | #^ source.nix punctuation.definition.attrset.nix -------------------------------------------------------------------------------- /syntaxes/tests/colon.nix: -------------------------------------------------------------------------------- 1 | [ { targets = [ "}:" ]; } ] 2 | -------------------------------------------------------------------------------- /syntaxes/tests/colon.nix.snap: -------------------------------------------------------------------------------- 1 | >[ { targets = [ "}:" ]; } ] 2 | #^ source.nix punctuation.definition.list.nix 3 | # ^ source.nix 4 | # ^ source.nix punctuation.definition.attrset.nix 5 | # ^ source.nix 6 | # ^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 7 | # ^ source.nix 8 | # ^ source.nix keyword.operator.bind.nix 9 | # ^ source.nix 10 | # ^ source.nix punctuation.definition.list.nix 11 | # ^ source.nix 12 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 13 | # ^^ source.nix string.quoted.double.nix 14 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 15 | # ^ source.nix 16 | # ^ source.nix punctuation.definition.list.nix 17 | # ^ source.nix punctuation.terminator.bind.nix 18 | # ^ source.nix 19 | # ^ source.nix punctuation.definition.attrset.nix 20 | # ^ source.nix 21 | # ^ source.nix punctuation.definition.list.nix 22 | > -------------------------------------------------------------------------------- /syntaxes/tests/colon2.nix: -------------------------------------------------------------------------------- 1 | nps.stacks.monitoring.prometheus.config = lib.mkIf cfg.enablePrometheusExport { 2 | scrape_configs = [ 3 | { 4 | job_name = "blocky"; 5 | honor_timestamps = true; 6 | metrics_path = "/metrics"; 7 | scheme = "http"; 8 | static_configs = [{targets = ["${name}:6000"];}]; 9 | } 10 | ]; 11 | }; 12 | 13 | nps.stacks.${name} = { 14 | settings = { 15 | prometheus = { 16 | enabled = cfg.enablePrometheusExport; 17 | level = "aggregated"; 18 | listen_address = "0.0.0.0"; 19 | listen_port = 6060; 20 | }; 21 | }; 22 | }; -------------------------------------------------------------------------------- /syntaxes/tests/colon2.nix.snap: -------------------------------------------------------------------------------- 1 | >nps.stacks.monitoring.prometheus.config = lib.mkIf cfg.enablePrometheusExport { 2 | #^^^ source.nix variable.parameter.name.nix 3 | # ^ source.nix keyword.operator.nix 4 | # ^^^^^^ source.nix variable.parameter.name.nix 5 | # ^ source.nix keyword.operator.nix 6 | # ^^^^^^^^^^ source.nix variable.parameter.name.nix 7 | # ^ source.nix keyword.operator.nix 8 | # ^^^^^^^^^^ source.nix variable.parameter.name.nix 9 | # ^ source.nix keyword.operator.nix 10 | # ^^^^^^ source.nix variable.parameter.name.nix 11 | # ^ source.nix 12 | # ^ source.nix invalid.illegal 13 | # ^ source.nix 14 | # ^^^ source.nix variable.parameter.name.nix 15 | # ^ source.nix keyword.operator.nix 16 | # ^^^^ source.nix variable.parameter.name.nix 17 | # ^ source.nix 18 | # ^^^ source.nix variable.parameter.name.nix 19 | # ^ source.nix keyword.operator.nix 20 | # ^^^^^^^^^^^^^^^^^^^^^^ source.nix variable.parameter.name.nix 21 | # ^ source.nix 22 | # ^ source.nix punctuation.definition.attrset-or-function.nix 23 | > scrape_configs = [ 24 | #^^ source.nix 25 | # ^^^^^^^^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 26 | # ^ source.nix 27 | # ^ source.nix keyword.operator.bind.nix 28 | # ^ source.nix 29 | # ^ source.nix punctuation.definition.list.nix 30 | > { 31 | #^^^^ source.nix 32 | # ^ source.nix punctuation.definition.attrset-or-function.nix 33 | > job_name = "blocky"; 34 | #^^^^^^ source.nix 35 | # ^^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 36 | # ^ source.nix 37 | # ^ source.nix keyword.operator.bind.nix 38 | # ^ source.nix 39 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 40 | # ^^^^^^ source.nix string.quoted.double.nix 41 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 42 | # ^ source.nix punctuation.terminator.bind.nix 43 | > honor_timestamps = true; 44 | #^^^^^^ source.nix 45 | # ^^^^^^^^^^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 46 | # ^ source.nix 47 | # ^ source.nix keyword.operator.bind.nix 48 | # ^ source.nix 49 | # ^^^^ source.nix constant.language.nix 50 | # ^ source.nix punctuation.terminator.bind.nix 51 | > metrics_path = "/metrics"; 52 | #^^^^^^ source.nix 53 | # ^^^^^^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 54 | # ^ source.nix 55 | # ^ source.nix keyword.operator.bind.nix 56 | # ^ source.nix 57 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 58 | # ^^^^^^^^ source.nix string.quoted.double.nix 59 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 60 | # ^ source.nix punctuation.terminator.bind.nix 61 | > scheme = "http"; 62 | #^^^^^^ source.nix 63 | # ^^^^^^ source.nix entity.other.attribute-name.multipart.nix 64 | # ^ source.nix 65 | # ^ source.nix keyword.operator.bind.nix 66 | # ^ source.nix 67 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 68 | # ^^^^ source.nix string.quoted.double.nix 69 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 70 | # ^ source.nix punctuation.terminator.bind.nix 71 | > static_configs = [{targets = ["${name}:6000"];}]; 72 | #^^^^^^ source.nix 73 | # ^^^^^^^^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 74 | # ^ source.nix 75 | # ^ source.nix keyword.operator.bind.nix 76 | # ^ source.nix 77 | # ^ source.nix punctuation.definition.list.nix 78 | # ^ source.nix punctuation.definition.attrset.nix 79 | # ^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 80 | # ^ source.nix 81 | # ^ source.nix keyword.operator.bind.nix 82 | # ^ source.nix 83 | # ^ source.nix punctuation.definition.list.nix 84 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 85 | # ^^ source.nix string.quoted.double.nix meta.embedded punctuation.section.embedded.begin.nix 86 | # ^^^^ source.nix string.quoted.double.nix meta.embedded variable.parameter.name.nix 87 | # ^ source.nix string.quoted.double.nix meta.embedded punctuation.section.embedded.end.nix 88 | # ^^^^^ source.nix string.quoted.double.nix 89 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 90 | # ^ source.nix punctuation.definition.list.nix 91 | # ^ source.nix punctuation.terminator.bind.nix 92 | # ^ source.nix punctuation.definition.attrset.nix 93 | # ^ source.nix punctuation.definition.list.nix 94 | # ^ source.nix punctuation.terminator.bind.nix 95 | > } 96 | #^^^^ source.nix 97 | # ^ source.nix punctuation.definition.attrset.nix 98 | > ]; 99 | #^^ source.nix 100 | # ^ source.nix punctuation.definition.list.nix 101 | # ^ source.nix punctuation.terminator.bind.nix 102 | >}; 103 | #^ source.nix punctuation.definition.attrset.nix 104 | # ^ source.nix invalid.illegal 105 | > 106 | >nps.stacks.${name} = { 107 | #^^^ source.nix variable.parameter.name.nix 108 | # ^ source.nix keyword.operator.nix 109 | # ^^^^^^ source.nix variable.parameter.name.nix 110 | # ^ source.nix keyword.operator.nix 111 | # ^^ source.nix meta.embedded punctuation.section.embedded.begin.nix 112 | # ^^^^ source.nix meta.embedded variable.parameter.name.nix 113 | # ^ source.nix meta.embedded punctuation.section.embedded.end.nix 114 | # ^ source.nix 115 | # ^ source.nix invalid.illegal 116 | # ^ source.nix 117 | # ^ source.nix punctuation.definition.attrset-or-function.nix 118 | > settings = { 119 | #^^ source.nix 120 | # ^^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 121 | # ^ source.nix 122 | # ^ source.nix keyword.operator.bind.nix 123 | # ^ source.nix 124 | # ^ source.nix punctuation.definition.attrset-or-function.nix 125 | > prometheus = { 126 | #^^^^ source.nix 127 | # ^^^^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 128 | # ^ source.nix 129 | # ^ source.nix keyword.operator.bind.nix 130 | # ^ source.nix 131 | # ^ source.nix punctuation.definition.attrset-or-function.nix 132 | > enabled = cfg.enablePrometheusExport; 133 | #^^^^^^ source.nix 134 | # ^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 135 | # ^ source.nix 136 | # ^ source.nix keyword.operator.bind.nix 137 | # ^ source.nix 138 | # ^^^ source.nix variable.parameter.name.nix 139 | # ^ source.nix keyword.operator.nix 140 | # ^^^^^^^^^^^^^^^^^^^^^^ source.nix variable.parameter.name.nix 141 | # ^ source.nix punctuation.terminator.bind.nix 142 | > level = "aggregated"; 143 | #^^^^^^ source.nix 144 | # ^^^^^ source.nix entity.other.attribute-name.multipart.nix 145 | # ^ source.nix 146 | # ^ source.nix keyword.operator.bind.nix 147 | # ^ source.nix 148 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 149 | # ^^^^^^^^^^ source.nix string.quoted.double.nix 150 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 151 | # ^ source.nix punctuation.terminator.bind.nix 152 | > listen_address = "0.0.0.0"; 153 | #^^^^^^ source.nix 154 | # ^^^^^^^^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 155 | # ^ source.nix 156 | # ^ source.nix keyword.operator.bind.nix 157 | # ^ source.nix 158 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 159 | # ^^^^^^^ source.nix string.quoted.double.nix 160 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 161 | # ^ source.nix punctuation.terminator.bind.nix 162 | > listen_port = 6060; 163 | #^^^^^^ source.nix 164 | # ^^^^^^^^^^^ source.nix entity.other.attribute-name.multipart.nix 165 | # ^ source.nix 166 | # ^ source.nix keyword.operator.bind.nix 167 | # ^ source.nix 168 | # ^^^^ source.nix constant.numeric.nix 169 | # ^ source.nix punctuation.terminator.bind.nix 170 | > }; 171 | #^^^^ source.nix 172 | # ^ source.nix punctuation.definition.attrset.nix 173 | # ^ source.nix punctuation.terminator.bind.nix 174 | > }; 175 | #^^ source.nix 176 | # ^ source.nix punctuation.definition.attrset.nix 177 | # ^ source.nix punctuation.terminator.bind.nix 178 | >}; 179 | #^ source.nix punctuation.definition.attrset.nix 180 | # ^ source.nix invalid.illegal -------------------------------------------------------------------------------- /syntaxes/tests/misc.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | let 3 | inherit (builtins) head tail isList isAttrs isInt attrNames; 4 | 5 | in 6 | 7 | with lib.lists; 8 | with lib.attrsets; 9 | with lib.strings; 10 | 11 | rec { 12 | 13 | # returns default if env var is not set 14 | maybeEnv = name: default: 15 | let value = builtins.getEnv name; in 16 | if value == "" then default else value; 17 | 18 | defaultMergeArg = x : y: if builtins.isAttrs y then 19 | y 20 | else 21 | (y x); 22 | defaultMerge = x: y: x // (defaultMergeArg x y); 23 | foldArgs = merger: f: init: x: 24 | let arg = (merger init (defaultMergeArg init x)); 25 | # now add the function with composed args already applied to the final attrs 26 | base = (setAttrMerge "passthru" {} (f arg) 27 | ( z: z // {__id_static="0.4553087592557379";__id_dynamic=builtins.hashFile "sha256" /Users/jeffhykin/repos/snowball/random.ignore; 28 | 29 | function = foldArgs merger f arg; 30 | args = (lib.attrByPath ["passthru" "args"] {} z) // x; 31 | } )); 32 | withStdOverrides = base // {__id_static="0.8985474209071187";__id_dynamic=builtins.hashFile "sha256" /Users/jeffhykin/repos/snowball/random.ignore; 33 | 34 | override = base.passthru.function; 35 | }; 36 | in 37 | withStdOverrides; 38 | 39 | 40 | # shortcut for attrByPath ["name"] default attrs 41 | maybeAttrNullable = maybeAttr; 42 | 43 | # shortcut for attrByPath ["name"] default attrs 44 | maybeAttr = name: default: attrs: attrs.${name} or default; 45 | 46 | 47 | # Return the second argument if the first one is true or the empty version 48 | # of the second argument. 49 | ifEnable = cond: val: 50 | if cond then val 51 | else if builtins.isList val then [] 52 | else if builtins.isAttrs val then {} 53 | # else if builtins.isString val then "" 54 | else if val == true || val == false then false 55 | else null; 56 | 57 | 58 | # Return true only if there is an attribute and it is true. 59 | checkFlag = attrSet: name: 60 | if name == "true" then true else 61 | if name == "false" then false else 62 | if (elem name (attrByPath ["flags"] [] attrSet)) then true else 63 | attrByPath [name] false attrSet ; 64 | 65 | 66 | # Input : attrSet, [ [name default] ... ], name 67 | # Output : its value or default. 68 | getValue = attrSet: argList: name: 69 | ( attrByPath [name] (if checkFlag attrSet name then true else 70 | if argList == [] then null else 71 | let x = builtins.head argList; in 72 | if (head x) == name then 73 | (head (tail x)) 74 | else (getValue attrSet 75 | (tail argList) name)) attrSet ); 76 | 77 | 78 | # Input : attrSet, [[name default] ...], [ [flagname reqs..] ... ] 79 | # Output : are reqs satisfied? It's asserted. 80 | checkReqs = attrSet: argList: condList: 81 | ( 82 | foldr lib.and true 83 | (map (x: let name = (head x); in 84 | 85 | ((checkFlag attrSet name) -> 86 | (foldr lib.and true 87 | (map (y: let val=(getValue attrSet argList y); in 88 | (val!=null) && (val!=false)) 89 | (tail x))))) condList)); 90 | 91 | 92 | # This function has O(n^2) performance. 93 | uniqList = { inputList, acc ? [] }: 94 | let go = xs: acc: 95 | if xs == [] 96 | then [] 97 | else let x = head xs; 98 | y = if elem x acc then [] else [x]; 99 | in y ++ go (tail xs) (y ++ acc); 100 | in go inputList acc; 101 | 102 | uniqListExt = { inputList, 103 | outputList ? [], 104 | getter ? (x: x), 105 | compare ? (x: y: x==y) }: 106 | if inputList == [] then outputList else 107 | let x = head inputList; 108 | isX = y: (compare (getter y) (getter x)); 109 | newOutputList = outputList ++ 110 | (if any isX outputList then [] else [x]); 111 | in uniqListExt {__id_static="0.5416861884942961";__id_dynamic=builtins.hashFile "sha256" /Users/jeffhykin/repos/snowball/random.ignore; 112 | outputList = newOutputList; 113 | inputList = (tail inputList); 114 | inherit getter compare; 115 | }; 116 | 117 | condConcat = name: list: checker: 118 | if list == [] then name else 119 | if checker (head list) then 120 | condConcat 121 | (name + (head (tail list))) 122 | (tail (tail list)) 123 | checker 124 | else condConcat 125 | name (tail (tail list)) checker; 126 | 127 | lazyGenericClosure = {startSet, operator}: 128 | let 129 | work = list: doneKeys: result: 130 | if list == [] then 131 | result 132 | else 133 | let x = head list; key = x.key; in 134 | if elem key doneKeys then 135 | work (tail list) doneKeys result 136 | else 137 | work (tail list ++ operator x) ([key] ++ doneKeys) ([x] ++ result); 138 | in 139 | work startSet [] []; 140 | 141 | innerModifySumArgs = f: x: a: b: if b == null then (f a b) // x else 142 | innerModifySumArgs f x (a // b); 143 | modifySumArgs = f: x: innerModifySumArgs f x {}; 144 | 145 | 146 | innerClosePropagation = acc: xs: 147 | if xs == [] 148 | then acc 149 | else let y = head xs; 150 | ys = tail xs; 151 | in if ! isAttrs y 152 | then innerClosePropagation acc ys 153 | else let acc' = [y] ++ acc; 154 | in innerClosePropagation 155 | acc' 156 | (uniqList {__id_static="0.43591725975550166";__id_dynamic=builtins.hashFile "sha256" /Users/jeffhykin/repos/snowball/random.ignore; 157 | inputList = (maybeAttrNullable "propagatedBuildInputs" [] y) 158 | ++ (maybeAttrNullable "propagatedNativeBuildInputs" [] y) 159 | ++ ys; 160 | acc = acc'; 161 | } 162 | ); 163 | 164 | closePropagationSlow = list: (uniqList {__id_static="0.4333385880390894";__id_dynamic=builtins.hashFile "sha256" /Users/jeffhykin/repos/snowball/random.ignore; 165 | inputList = (innerClosePropagation [] list);}); 166 | 167 | # This is an optimisation of lib.closePropagation which avoids the O(n^2) behavior 168 | # Using a list of derivations, it generates the full closure of the propagatedXXXBuildInputs 169 | # The ordering / sorting / comparison is done based on the `outPath` 170 | # attribute of each derivation. 171 | # On some benchmarks, it performs up to 15 times faster than lib.closePropagation. 172 | # See https://github.com/NixOS/nixpkgs/pull/194391 for details. 173 | closePropagationFast = list: 174 | builtins.map (x: x.val) (builtins.genericClosure {__id_static="0.4393836786265646";__id_dynamic=builtins.hashFile "sha256" /Users/jeffhykin/repos/snowball/random.ignore; 175 | 176 | startSet = builtins.map (x: {__id_static="0.42616742269720653";__id_dynamic=builtins.hashFile "sha256" /Users/jeffhykin/repos/snowball/random.ignore; 177 | 178 | key = x.outPath; 179 | val = x; 180 | }) (builtins.filter (x: x != null) list); 181 | operator = item: 182 | if !builtins.isAttrs item.val then 183 | [ ] 184 | else 185 | builtins.concatMap (x: 186 | if x != null then [{__id_static="0.7684626401674357";__id_dynamic=builtins.hashFile "sha256" /Users/jeffhykin/repos/snowball/random.ignore; 187 | 188 | key = x.outPath; 189 | val = x; 190 | }] else 191 | [ ]) ((item.val.propagatedBuildInputs or [ ]) 192 | ++ (item.val.propagatedNativeBuildInputs or [ ])); 193 | }); 194 | 195 | closePropagation = if builtins ? genericClosure 196 | then closePropagationFast 197 | else closePropagationSlow; 198 | 199 | # calls a function (f attr value ) for each record item. returns a list 200 | mapAttrsFlatten = f: r: map (attr: f attr r.${attr}) (attrNames r); 201 | 202 | # attribute set containing one attribute 203 | nvs = name: value: listToAttrs [ (nameValuePair name value) ]; 204 | # adds / replaces an attribute of an attribute set 205 | setAttr = set: name: v: set // (nvs name v); 206 | 207 | # setAttrMerge (similar to mergeAttrsWithFunc but only merges the values of a particular name) 208 | # setAttrMerge "a" [] { a = [2];} (x: x ++ [3]) -> { a = [2 3]; } 209 | # setAttrMerge "a" [] { } (x: x ++ [3]) -> { a = [ 3]; } 210 | setAttrMerge = name: default: attrs: f: 211 | setAttr attrs name (f (maybeAttr name default attrs)); 212 | 213 | # Using f = a: b = b the result is similar to // 214 | # merge attributes with custom function handling the case that the attribute 215 | # exists in both sets 216 | mergeAttrsWithFunc = f: set1: set2: 217 | foldr (n: set: if set ? ${n} 218 | then setAttr set n (f set.${n} set2.${n}) 219 | else set ) 220 | (set2 // set1) (attrNames set2); 221 | 222 | # merging two attribute set concatenating the values of same attribute names 223 | # eg { a = 7; } { a = [ 2 3 ]; } becomes { a = [ 7 2 3 ]; } 224 | mergeAttrsConcatenateValues = mergeAttrsWithFunc ( a: b: (toList a) ++ (toList b) ); 225 | 226 | # merges attributes using //, if a name exists in both attributes 227 | # an error will be triggered unless its listed in mergeLists 228 | # so you can mergeAttrsNoOverride { buildInputs = [a]; } { buildInputs = [a]; } {} to get 229 | # { buildInputs = [a b]; } 230 | # merging buildPhase doesn't really make sense. The cases will be rare where appending /prefixing will fit your needs? 231 | # in these cases the first buildPhase will override the second one 232 | # ! deprecated, use mergeAttrByFunc instead 233 | mergeAttrsNoOverride = { mergeLists ? ["buildInputs" "propagatedBuildInputs"], 234 | overrideSnd ? [ "buildPhase" ] 235 | }: attrs1: attrs2: 236 | foldr (n: set: 237 | setAttr set n ( if set ? ${n} 238 | then # merge 239 | if elem n mergeLists # attribute contains list, merge them by concatenating 240 | then attrs2.${n} ++ attrs1.${n} 241 | else if elem n overrideSnd 242 | then attrs1.${n} 243 | else throw "error mergeAttrsNoOverride, attribute ${n} given in both attributes - no merge func defined" 244 | else attrs2.${n} # add attribute not existing in attr1 245 | )) attrs1 (attrNames attrs2); 246 | 247 | 248 | # example usage: 249 | # mergeAttrByFunc { 250 | # inherit mergeAttrBy; # defined below 251 | # buildInputs = [ a b ]; 252 | # } { 253 | # buildInputs = [ c d ]; 254 | # }; 255 | # will result in 256 | # { mergeAttrsBy = [...]; buildInputs = [ a b c d ]; } 257 | # is used by defaultOverridableDelayableArgs and can be used when composing using 258 | # foldArgs, composedArgsAndFun or applyAndFun. Example: composableDerivation in all-packages.nix 259 | mergeAttrByFunc = x: y: 260 | let 261 | mergeAttrBy2 = {__id_static="0.11202360130761346";__id_dynamic=builtins.hashFile "sha256" /Users/jeffhykin/repos/snowball/random.ignore; 262 | mergeAttrBy = lib.mergeAttrs; } 263 | // (maybeAttr "mergeAttrBy" {} x) 264 | // (maybeAttr "mergeAttrBy" {} y); in 265 | foldr lib.mergeAttrs {} [ 266 | x y 267 | (mapAttrs ( a: v: # merge special names using given functions 268 | if x ? ${a} 269 | then if y ? ${a} 270 | then v x.${a} y.${a} # both have attr, use merge func 271 | else x.${a} # only x has attr 272 | else y.${a} # only y has attr) 273 | ) (removeAttrs mergeAttrBy2 274 | # don't merge attrs which are neither in x nor y 275 | (filter (a: ! x ? ${a} && ! y ? ${a}) 276 | (attrNames mergeAttrBy2)) 277 | ) 278 | ) 279 | ]; 280 | mergeAttrsByFuncDefaults = foldl mergeAttrByFunc {__id_static="0.6726806392463629";__id_dynamic=builtins.hashFile "sha256" /Users/jeffhykin/repos/snowball/random.ignore; 281 | inherit mergeAttrBy; }; 282 | mergeAttrsByFuncDefaultsClean = list: removeAttrs (mergeAttrsByFuncDefaults list) ["mergeAttrBy"]; 283 | 284 | # sane defaults (same name as attr name so that inherit can be used) 285 | mergeAttrBy = # { buildInputs = concatList; [...]; passthru = mergeAttr; [..]; } 286 | listToAttrs (map (n: nameValuePair n lib.concat) 287 | [ "nativeBuildInputs" "buildInputs" "propagatedBuildInputs" "configureFlags" "prePhases" "postAll" "patches" ]) 288 | // listToAttrs (map (n: nameValuePair n lib.mergeAttrs) [ "passthru" "meta" "cfg" "flags" ]) 289 | // listToAttrs (map (n: nameValuePair n (a: b: "${a}\n${b}") ) [ "preConfigure" "postInstall" ]) 290 | ; 291 | 292 | nixType = x: 293 | if isAttrs x then 294 | if x ? outPath then "derivation" 295 | else "attrs" 296 | else if lib.isFunction x then "function" 297 | else if isList x then "list" 298 | else if x == true then "bool" 299 | else if x == false then "bool" 300 | else if x == null then "null" 301 | else if isInt x then "int" 302 | else "string"; 303 | 304 | /* deprecated: 305 | 306 | For historical reasons, imap has an index starting at 1. 307 | 308 | But for consistency with the rest of the library we want an index 309 | starting at zero. 310 | */ 311 | imap = imap1; 312 | 313 | # Fake hashes. Can be used as hash placeholders, when computing hash ahead isn't trivial 314 | fakeHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; 315 | fakeSha256 = "0000000000000000000000000000000000000000000000000000000000000000"; 316 | fakeSha512 = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; 317 | } -------------------------------------------------------------------------------- /syntaxes/tests/sample.nix: -------------------------------------------------------------------------------- 1 | # SYNTAX TEST "source.nix" "sample testcase" 2 | 3 | let 4 | a = abort "will never happen"; 5 | b = "hello"; 6 | c = "world"; 7 | path = ./relative/path 8 | sp_path = ./relative/${path} 9 | in b + c -------------------------------------------------------------------------------- /syntaxes/tests/sample.nix.snap: -------------------------------------------------------------------------------- 1 | ># SYNTAX TEST "source.nix" "sample testcase" 2 | #^ source.nix comment.line.number-sign.nix 3 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ source.nix comment.line.number-sign.nix 4 | > 5 | >let 6 | #^^^ source.nix keyword.other.nix 7 | > a = abort "will never happen"; 8 | #^^ source.nix 9 | # ^ source.nix entity.other.attribute-name.multipart.nix 10 | # ^ source.nix 11 | # ^ source.nix keyword.operator.bind.nix 12 | # ^ source.nix 13 | # ^^^^^ source.nix support.function.nix 14 | # ^ source.nix 15 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 16 | # ^^^^^^^^^^^^^^^^^ source.nix string.quoted.double.nix 17 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 18 | # ^ source.nix punctuation.terminator.bind.nix 19 | > b = "hello"; 20 | #^^ source.nix 21 | # ^ source.nix entity.other.attribute-name.multipart.nix 22 | # ^ source.nix 23 | # ^ source.nix keyword.operator.bind.nix 24 | # ^ source.nix 25 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 26 | # ^^^^^ source.nix string.quoted.double.nix 27 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 28 | # ^ source.nix punctuation.terminator.bind.nix 29 | > c = "world"; 30 | #^^ source.nix 31 | # ^ source.nix entity.other.attribute-name.multipart.nix 32 | # ^ source.nix 33 | # ^ source.nix keyword.operator.bind.nix 34 | # ^ source.nix 35 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.start.nix 36 | # ^^^^^ source.nix string.quoted.double.nix 37 | # ^ source.nix string.quoted.double.nix punctuation.definition.string.double.end.nix 38 | # ^ source.nix punctuation.terminator.bind.nix 39 | > path = ./relative/path 40 | #^^ source.nix 41 | # ^^^^ source.nix entity.other.attribute-name.multipart.nix 42 | # ^ source.nix 43 | # ^ source.nix keyword.operator.bind.nix 44 | # ^ source.nix 45 | # ^^^^^^^^^^^^^^^ source.nix string.unquoted.path.nix 46 | > sp_path = ./relative/${path} 47 | #^^ source.nix 48 | # ^^^^^^^ source.nix variable.parameter.name.nix 49 | # ^ source.nix 50 | # ^ source.nix invalid.illegal 51 | # ^ source.nix 52 | # ^^^^^^^^^^ source.nix string.unquoted.path.nix 53 | # ^ source.nix keyword.operator.nix 54 | # ^^ source.nix meta.embedded punctuation.section.embedded.begin.nix 55 | # ^^^^ source.nix meta.embedded variable.parameter.name.nix 56 | # ^ source.nix meta.embedded punctuation.section.embedded.end.nix 57 | >in b + c 58 | #^^ source.nix invalid.illegal.reserved.nix 59 | # ^ source.nix 60 | # ^ source.nix variable.parameter.name.nix 61 | # ^ source.nix 62 | # ^ source.nix keyword.operator.nix 63 | # ^ source.nix 64 | # ^ source.nix variable.parameter.name.nix -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2018", 5 | "outDir": "dist", 6 | "lib": [ 7 | "es2018" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | /* Strict Type-Checking Option */ 12 | "strict": true /* enable all strict type-checking options */, 13 | /* Additional Checks */ 14 | "noUnusedParameters": true, /* Report errors on unused parameters. */ 15 | "noUnusedLocals": true /* Report errors on unused locals. */ 16 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 17 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 18 | }, 19 | "exclude": [ 20 | "node_modules", 21 | ".vscode-test" 22 | ] 23 | } --------------------------------------------------------------------------------