├── .gitattributes ├── .github ├── actions │ └── setup-tools │ │ └── action.yml ├── dependabot.yml ├── scripts │ └── get-release-notes.js └── workflows │ ├── build-main-branch.yml │ ├── build.yml │ ├── bump-version.yml │ └── publish-to-jetbrains.yml ├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── icon.svg └── runConfigurations │ ├── All_Tests.xml │ └── IntelliJ_IDEA_Community_Edition.xml ├── CHANGELOG.md ├── LICENSE ├── NOTICE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml ├── plugins │ ├── build.gradle.kts │ ├── settings.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ ├── ChangePropertyTask.kt │ │ ├── MetadataTask.kt │ │ ├── PluginVersions.kt │ │ ├── local.bump-version.gradle.kts │ │ └── local.jbr-guidance.gradle.kts └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── src ├── main ├── assembly │ └── nix-idea.xml ├── java │ └── org │ │ └── nixos │ │ └── idea │ │ ├── file │ │ ├── NixFile.java │ │ └── NixFileType.java │ │ ├── format │ │ └── NixExternalFormatter.java │ │ ├── icon │ │ └── NixIcons.java │ │ ├── imports │ │ └── NixFilePathReferenceContributor.kt │ │ ├── lang │ │ ├── NixBraceMatcher.java │ │ ├── NixCommenter.java │ │ ├── NixLanguage.java │ │ ├── NixLexer.java │ │ ├── NixMoveElementLeftRightHandler.java │ │ ├── NixParserDefinition.java │ │ ├── NixQuoteHandler.java │ │ ├── NixSpellcheckingStrategy.java │ │ ├── builtins │ │ │ └── NixBuiltin.java │ │ ├── highlighter │ │ │ ├── NixHighlightVisitor.java │ │ │ ├── NixHighlightVisitorDelegate.java │ │ │ ├── NixRainbowVisitor.java │ │ │ ├── NixSyntaxHighlighter.java │ │ │ ├── NixSyntaxHighlighterFactory.java │ │ │ └── NixTextAttributes.java │ │ └── references │ │ │ ├── NixNavigationTarget.java │ │ │ ├── NixScopeReference.java │ │ │ ├── NixSymbolDeclaration.java │ │ │ ├── NixSymbolReference.java │ │ │ ├── NixUsage.java │ │ │ ├── NixUsageSearcher.java │ │ │ ├── Scope.java │ │ │ └── symbol │ │ │ ├── Commons.java │ │ │ ├── NixBuiltinSymbol.java │ │ │ ├── NixSymbol.java │ │ │ └── NixUserSymbol.java │ │ ├── lsp │ │ ├── NixLspServerDescriptor.java │ │ ├── NixLspServerSupportProvider.java │ │ ├── NixLspSettings.kt │ │ └── NixLspSettingsConfigurable.kt │ │ ├── psi │ │ ├── NixDeclarationHost.java │ │ ├── NixElementFactory.java │ │ ├── NixElementType.java │ │ ├── NixPsiElement.java │ │ ├── NixPsiUtil.java │ │ ├── NixTokenSets.java │ │ ├── NixTokenType.java │ │ └── impl │ │ │ ├── AbstractNixDeclarationHost.java │ │ │ ├── AbstractNixPsiElement.java │ │ │ ├── NixExprStdPathMixin.kt │ │ │ └── NixParserUtil.java │ │ ├── settings │ │ ├── NixExternalFormatterSettings.kt │ │ ├── NixIDEASettings.form │ │ ├── NixIDEASettings.java │ │ ├── NixStoragePaths.java │ │ ├── NixSymbolSettings.kt │ │ ├── SimplePersistentStateComponentHelper.kt │ │ └── ui │ │ │ ├── CommandSuggestionsPopup.java │ │ │ ├── NixColorSettingsPage.java │ │ │ ├── NixLangSettingsConfigurable.kt │ │ │ ├── NixSymbolConfigurable.kt │ │ │ └── UiDslExtensions.kt │ │ └── util │ │ ├── NixPathVerifier.java │ │ ├── NixStringUtil.java │ │ ├── NixVersion.java │ │ └── TextRangeFactory.java ├── lang │ ├── Nix.bnf │ └── Nix.flex └── resources │ ├── META-INF │ ├── nix-idea-ultimate.xml │ ├── plugin.xml │ ├── pluginIcon.svg │ └── pluginIcon_dark.svg │ ├── colorSchemes │ ├── NixDarcula.xml │ └── NixDefault.xml │ └── icons │ ├── nixSnowflake.svg │ └── nixSnowflake_dark.svg └── test ├── java └── org │ └── nixos │ └── idea │ ├── NixTestExecutionPolicy.java │ ├── _testutil │ ├── EdtExtension.java │ ├── EdtExtensionTest.java │ ├── ExtensionTestUtil.java │ ├── IdeaPlatformExtension.java │ ├── Markers.java │ ├── MarkersTest.java │ ├── ReflectionUtils.java │ ├── TestFactoryDsl.kt │ └── WithIdeaPlatform.java │ ├── lang │ ├── LexerFilesTest.java │ ├── LexerTest.java │ ├── NixCommenterTest.java │ ├── NixMoveElementLeftRightHandlerTest.java │ ├── NixQuoteHandlerTest.java │ ├── ParsingFailTest.java │ ├── ParsingTest.java │ ├── highlighter │ │ ├── NixHighlightVisitorTest.java │ │ ├── NixRainbowVisitorTest.java │ │ ├── NixSyntaxHighlighterTest.java │ │ └── NixTextAttributesTest.java │ └── references │ │ ├── AbstractSymbolNavigationTests.kt │ │ ├── SymbolNavigationTest.kt │ │ └── SymbolTestHelper.java │ ├── psi │ ├── NixElementFactoryTest.java │ └── NixPsiUtilTest.java │ ├── settings │ └── ui │ │ └── NixColorSettingsPageTest.java │ └── util │ └── NixStringUtilTest.java └── testData ├── ParsingFailTest ├── AntiquotationStateSynchronization1.nix ├── AntiquotationStateSynchronization1.txt ├── AntiquotationStateSynchronization2.nix ├── AntiquotationStateSynchronization2.txt ├── Comment.nix ├── Comment.txt ├── Empty.nix ├── Empty.txt ├── IncompleteExpressionsInBraces.nix ├── IncompleteExpressionsInBraces.txt ├── MissingSemicolon.nix ├── MissingSemicolon.txt ├── MissingSemicolonTrap.nix ├── MissingSemicolonTrap.txt ├── RecWithoutSet.nix ├── RecWithoutSet.txt ├── RecoverFromAntiquotation.nix ├── RecoverFromAntiquotation.txt ├── RecoverFromAssertCondition.nix ├── RecoverFromAssertCondition.txt ├── RecoverFromIfCondition.nix ├── RecoverFromIfCondition.txt ├── RecoverFromIfThenExpression.nix ├── RecoverFromIfThenExpression.txt ├── RecoverFromLetBinding.nix ├── RecoverFromLetBinding.txt ├── RecoverFromListItem.nix ├── RecoverFromListItem.txt ├── RecoverFromParens.nix ├── RecoverFromParens.txt ├── RecoverFromParensWithValidSubexpressions.nix ├── RecoverFromParensWithValidSubexpressions.txt ├── RecoverFromSetBinding.nix ├── RecoverFromSetBinding.txt ├── RecoverFromWith.nix └── RecoverFromWith.txt └── ParsingTest ├── Assertion.lexer.txt ├── Assertion.nix ├── Assertion.txt ├── Boolean.lexer.txt ├── Boolean.nix ├── Boolean.txt ├── Function.lexer.txt ├── Function.nix ├── Function.txt ├── FunctionEmptySet.lexer.txt ├── FunctionEmptySet.nix ├── FunctionEmptySet.txt ├── FunctionTrailingComma.lexer.txt ├── FunctionTrailingComma.nix ├── FunctionTrailingComma.txt ├── Identifier.lexer.txt ├── Identifier.nix ├── Identifier.txt ├── If.lexer.txt ├── If.nix ├── If.txt ├── LegacyLet.lexer.txt ├── LegacyLet.nix ├── LegacyLet.txt ├── LegacyLetInList.lexer.txt ├── LegacyLetInList.nix ├── LegacyLetInList.txt ├── LegacyOrAsArgument.lexer.txt ├── LegacyOrAsArgument.nix ├── LegacyOrAsArgument.txt ├── LegacyOrAsAttribute.lexer.txt ├── LegacyOrAsAttribute.nix ├── LegacyOrAsAttribute.txt ├── LegacyOrInList.lexer.txt ├── LegacyOrInList.nix ├── LegacyOrInList.txt ├── Let.lexer.txt ├── Let.nix ├── Let.txt ├── LetEmpty.lexer.txt ├── LetEmpty.nix ├── LetEmpty.txt ├── List.lexer.txt ├── List.nix ├── List.txt ├── ListWithFunction.lexer.txt ├── ListWithFunction.nix ├── ListWithFunction.txt ├── Null.lexer.txt ├── Null.nix ├── Null.txt ├── Number.lexer.txt ├── Number.nix ├── Number.txt ├── Operators.lexer.txt ├── Operators.nix ├── Operators.txt ├── OperatorsAssociativity.lexer.txt ├── OperatorsAssociativity.nix ├── OperatorsAssociativity.txt ├── Path.lexer.txt ├── Path.nix ├── Path.txt ├── RecursiveSet.lexer.txt ├── RecursiveSet.nix ├── RecursiveSet.txt ├── Set.lexer.txt ├── Set.nix ├── Set.txt ├── SetAccess.lexer.txt ├── SetAccess.nix ├── SetAccess.txt ├── String.lexer.txt ├── String.nix ├── String.txt ├── StringWithAntiquotation.lexer.txt ├── StringWithAntiquotation.nix ├── StringWithAntiquotation.txt ├── StringWithEscapeSequences.lexer.txt ├── StringWithEscapeSequences.nix ├── StringWithEscapeSequences.txt ├── StringWithMultipleLines.lexer.txt ├── StringWithMultipleLines.nix ├── StringWithMultipleLines.txt ├── Uri.lexer.txt ├── Uri.nix ├── Uri.txt ├── With.lexer.txt ├── With.nix └── With.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Keep Gradle wrapper distribution as is 2 | /gradlew binary 3 | /gradlew.bat binary 4 | /gradle/wrapper/gradle-wrapper.jar binary 5 | 6 | # Source file configuration 7 | *.java diff=java 8 | -------------------------------------------------------------------------------- /.github/actions/setup-tools/action.yml: -------------------------------------------------------------------------------- 1 | name: Set up Build Tools 2 | description: Set up and configure Java and Gradle 3 | inputs: 4 | publish-caches: 5 | description: Whether this job shall be used to update the caches 6 | default: 'false' 7 | runs: 8 | using: composite 9 | steps: 10 | - name: Set up JDK 17 11 | uses: actions/setup-java@v4 12 | with: 13 | java-version: 17 14 | distribution: temurin 15 | - name: Set up Gradle 16 | uses: gradle/actions/setup-gradle@v4 17 | with: 18 | cache-read-only: ${{ inputs.publish-caches != 'true' }} 19 | validate-wrappers: false 20 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /.github/scripts/get-release-notes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = async ({github, context, core, outputFile, releaseTagInput, allowFallbackToLatest}) => { 4 | const { RELEASE_TAG_INPUT, ALLOW_FALLBACK_TO_LATEST } = process.env; 5 | const fs = require('fs'); 6 | const owner = context.repo.owner; 7 | const repo = context.repo.repo; 8 | 9 | if (!outputFile) { 10 | throw new Error("outputFile not specified"); 11 | } 12 | 13 | let releaseNote; 14 | if (context.eventName === 'release') { 15 | releaseNote = context.payload.release.body; 16 | } 17 | else if (releaseTagInput && context.payload.inputs[releaseTagInput]) { 18 | const tag = context.payload.inputs[releaseTagInput]; 19 | try { 20 | const response = await github.rest.repos.getReleaseByTag({owner, repo, tag}); 21 | releaseNote = response.data.body; 22 | } 23 | catch (e) { 24 | if (e.status === 404) { 25 | core.setFailed(`No release with tag '${tag}' has been found.`); 26 | return; 27 | } 28 | else { 29 | throw e; 30 | } 31 | } 32 | } 33 | else if (allowFallbackToLatest) { 34 | const response = await github.rest.repos.getLatestRelease({owner, repo}); 35 | releaseNote = response.data.body; 36 | } 37 | else { 38 | throw new Error("No release tag specified and allowFallbackToLatest not set"); 39 | } 40 | 41 | core.info(`Release notes:\n${releaseNote}`); 42 | fs.writeFileSync(outputFile, releaseNote, { encoding: 'utf8', flag: 'wx' }); 43 | } 44 | -------------------------------------------------------------------------------- /.github/workflows/bump-version.yml: -------------------------------------------------------------------------------- 1 | name: Bump Version 2 | 3 | on: 4 | release: 5 | types: [ released ] 6 | workflow_dispatch: 7 | inputs: 8 | release_tag: 9 | description: 'Use release notes of' 10 | type: string 11 | required: false 12 | 13 | jobs: 14 | bump-version: 15 | 16 | name: Bump version and update changelog 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | # Setup environment 21 | - name: Checkout repository 22 | uses: actions/checkout@v4 23 | - name: Set up build tools 24 | uses: ./.github/actions/setup-tools 25 | # Fail if the release was not triggered from the master branch 26 | - name: Verify branch 27 | if: github.event_name == 'release' 28 | run: | 29 | if \ 30 | git fetch --depth=1 origin refs/heads/master && \ 31 | [ "$(git show-ref -s refs/heads/master)" != "$(git show-ref -s HEAD)" ] 32 | then 33 | msg="The release does not point to the master branch. This means the" 34 | msg="$msg branch has been updated after the release, or the release" 35 | msg="$msg was created on a different branch. Please trigger this" 36 | msg="$msg workflow manually on the correct branch." 37 | echo "::error::$msg" 38 | exit 1 39 | fi 40 | # Update files 41 | - name: Obtain release notes 42 | uses: actions/github-script@v7 43 | with: 44 | script: | 45 | await require('.github/scripts/get-release-notes.js')({ 46 | github, context, core, 47 | outputFile: 'release_note.md', 48 | releaseTagInput: 'release_tag', 49 | allowFallbackToLatest: true, 50 | }); 51 | - name: Update files with Gradle 52 | run: ./gradlew --stacktrace metadata patchChangelog --release-note="$( 2 | 3 | 31 | 32 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/runConfigurations/All_Tests.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 17 | 19 | true 20 | true 21 | false 22 | false 23 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/runConfigurations/IntelliJ_IDEA_Community_Edition.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 16 | 18 | true 19 | true 20 | false 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | License Notice 2 | 3 | NIX SNOWFLAKE 4 | 5 | This project contains variants of the Nix Snowflake (the logo of NixOS). 6 | The Nix Snowflake is designed by Tim Cuthbertson (@timbertson) and is 7 | made available under a CC-BY license. 8 | 9 | Origin: https://github.com/NixOS/nixos-artwork/tree/master/logo 10 | License: https://creativecommons.org/licenses/by/4.0/ 11 | 12 | The image files within this repository may have been modified to comply 13 | with JetBrains' Guidelines. The modifications may include resizing the 14 | image, refitting the image, and compressing the image by removing 15 | invisible elements. 16 | 17 | .idea/icon.svg 18 | src/main/resources/META-INF/pluginIcon.svg 19 | src/main/resources/META-INF/pluginIcon_dark.svg 20 | src/main/resources/icons/nixSnowflake.svg 21 | src/main/resources/icons/nixSnowflake_dark.svg 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NixIDEA - A Nix language plugin for IntelliJ IDEA 2 | 3 | [![Build Status](https://github.com/NixOS/nix-idea/actions/workflows/build-main-branch.yml/badge.svg)][build-status] 4 | [![Version](https://img.shields.io/jetbrains/plugin/v/nix-idea)][marketplace] 5 | 6 | 7 | 8 | This plugin has the goal of being generally useful when working with nixpkgs/NixOS/nixops. 9 | It currently adds support for the Nix language. 10 | The following features are available: 11 | 12 | * Syntax Highlighting 13 | * Real time detection of syntax errors 14 | 15 | We would also like to provide additional support for Nix/NixOS/NixOps, 16 | but the following features are currently **not implemented**: 17 | 18 | * Linting, code completion, formatting 19 | * Profile management 20 | * Run configurations 21 | * Templates for common usage patterns 22 | 23 | 24 | 25 | ## Install 26 | 27 | ### From JetBrains marketplace 28 | 29 | The plugin can be found at the Jetbrains plugin repository as 30 | [NixIDEA][marketplace]. 31 | 32 | * Goto **File > Settings > Plugins > Marketplace** 33 | * Type **NixIDEA** into the search bar 34 | * Click **Install** 35 | 36 | ### From ZIP file 37 | 38 | You can also install the plugin from a ZIP file. 39 | 40 | * Goto **File > Settings > Plugins** 41 | * Click onto the **wheel icon** on the top 42 | * Choose **Install Plugin from Disk** 43 | 44 | You can find corresponding ZIP files [on GitHub][releases] or build them 45 | yourself as described below. 46 | 47 | ## Build 48 | 49 | ### Build preparation 50 | 51 | Follow the following steps before you build the project the first time. 52 | 53 | * Clone the repository 54 | * Ensure that you have a JDK for Java 17 or higher on your PATH 55 | * Only on NixOS: Setup JetBrains Runtime (JBR) from `` 56 | ```sh 57 | nix-build '' -A jetbrains.jdk -o jbr 58 | ``` 59 | 60 | ### Build execution 61 | 62 | After you have completed the preparation, you can build the plugin by 63 | running the `build` task in Gradle. 64 | 65 | ```sh 66 | ./gradlew build 67 | ``` 68 | 69 | You should then find the plugin at 70 | `build/distributions/NixIDEA-.zip`. 71 | 72 | ## Credits 73 | 74 | The *Nix Snowflake* (logo of NixOS) is designed by Tim Cuthbertson (@timbertson). 75 | It is made available under [CC-BY license](https://creativecommons.org/licenses/by/4.0/) 76 | at [NixOS/nixos-artwork](https://github.com/NixOS/nixos-artwork/tree/master/logo). 77 | The variants used by this plugin may have been modified to comply with JetBrains' Guidelines. 78 | 79 | [build-status]: 80 | 81 | "Latest builds at GitHub Actions" 82 | [marketplace]: 83 | 84 | "NixIDEA on JetBrains Marketplace" 85 | [releases]: 86 | 87 | "Releases · NixOS/nix-idea" 88 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # IntelliJ Platform Artifacts Repositories 2 | # -> https://www.jetbrains.org/intellij/sdk/docs/reference_guide/intellij_artifacts.html 3 | 4 | pluginGroup = org.nixos.idea 5 | pluginName = NixIDEA 6 | pluginVersion = 0.4.0.18 7 | pluginSinceBuild = 241 8 | pluginUntilBuild = 251.* 9 | 10 | platformType = IU 11 | platformVersion = 2024.1.6 12 | 13 | # Gradle Configuration 14 | # -> https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties 15 | org.gradle.parallel=true 16 | org.gradle.caching=true 17 | org.gradle.configuration-cache=true 18 | 19 | # Use the stdlib of Kotlin which is bundled with IDEA 20 | # -> https://plugins.jetbrains.com/docs/intellij/using-kotlin.html#kotlin-standard-library 21 | kotlin.stdlib.default.dependency = false 22 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | # Gradle Version Catalog 2 | # -> https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format 3 | 4 | [libraries] 5 | jetbrains-annotations = { module = "org.jetbrains:annotations", version = "24.1.0" } 6 | junit5-bom = { module = "org.junit:junit-bom", version = "5.9.1" } 7 | junit5-jupiter = { module = "org.junit.jupiter:junit-jupiter" } 8 | junit5-platform-testkit = { module = "org.junit.platform:junit-platform-testkit" } 9 | junit5-vintage-engine = { module = "org.junit.vintage:junit-vintage-engine" } 10 | junit4 = { module = "junit:junit", version = "4.13.2" } 11 | 12 | [plugins] 13 | # read more: https://github.com/JetBrains/intellij-platform-gradle-plugin 14 | jetbrains-intellij-platform = { id = "org.jetbrains.intellij.platform", version = "2.0.1" } 15 | # read more: https://github.com/JetBrains/gradle-changelog-plugin 16 | jetbrains-changelog = { id = "org.jetbrains.changelog", version = "2.2.0" } 17 | # read more: https://github.com/JetBrains/gradle-grammar-kit-plugin 18 | jetbrains-grammarkit = { id = "org.jetbrains.grammarkit", version = "2022.3.2.2" } 19 | -------------------------------------------------------------------------------- /gradle/plugins/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | repositories { 6 | gradlePluginPortal() 7 | } 8 | 9 | dependencies { 10 | implementation(plugin(libs.plugins.jetbrains.intellij.platform)) 11 | } 12 | 13 | /** 14 | * Maps plugin dependencies to its maven coordinates. 15 | * 16 | * Hopefully, there will be native support for adding plugins as a dependency in the future. 17 | * See [Gradle Issue #17963 – Accept plugin declarations from version catalog also as libraries](https://github.com/gradle/gradle/issues/17963). 18 | */ 19 | fun plugin(pluginProvider: Provider): Provider> { 20 | return pluginProvider.map { 21 | val id = it.pluginId 22 | mapOf( 23 | "group" to id, 24 | "name" to "$id.gradle.plugin", // PLUGIN_MARKER_SUFFIX 25 | "version" to it.version.requiredVersion, 26 | ) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /gradle/plugins/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencyResolutionManagement { 2 | // Reuse version catalog from the main build. 3 | versionCatalogs { 4 | create("libs", { from(files("../libs.versions.toml")) }) 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /gradle/plugins/src/main/kotlin/ChangePropertyTask.kt: -------------------------------------------------------------------------------- 1 | import org.gradle.api.DefaultTask 2 | import org.gradle.api.file.ProjectLayout 3 | import org.gradle.api.model.ObjectFactory 4 | import org.gradle.api.tasks.Input 5 | import org.gradle.api.tasks.OutputFile 6 | import org.gradle.api.tasks.TaskAction 7 | import org.gradle.api.tasks.UntrackedTask 8 | import org.gradle.kotlin.dsl.property 9 | import javax.inject.Inject 10 | 11 | /** 12 | * Replaces the value of [propertyName] in the given [propertiesFile]. 13 | * The old value given by [oldValue] is replaced by the value given by [newValue]. 14 | */ 15 | @UntrackedTask(because = "Changes project files in-place") 16 | abstract class ChangePropertyTask @Inject constructor( 17 | objects: ObjectFactory, 18 | layout: ProjectLayout, 19 | ) : DefaultTask() { 20 | 21 | @get:Input 22 | val oldValue = objects.property() 23 | 24 | @get:Input 25 | val newValue = objects.property() 26 | 27 | @get:Input 28 | val propertyName = objects.property() 29 | 30 | @get:OutputFile 31 | val propertiesFile = objects.fileProperty() 32 | .convention(layout.projectDirectory.file("gradle.properties")) 33 | 34 | @TaskAction 35 | fun run() { 36 | val escapedName = Regex.escape(propertyName.get()) 37 | val escapedOldValue = Regex.escape(oldValue.get()) 38 | val escapedReplacement = Regex.escapeReplacement(newValue.get()) 39 | 40 | val file = propertiesFile.get().asFile 41 | file.writeText( 42 | file.readText().replace( 43 | Regex( 44 | "^(\\s*$escapedName\\s*=\\s*)$escapedOldValue(\\s*)$", 45 | RegexOption.MULTILINE, 46 | ), 47 | "$1${escapedReplacement}$2", 48 | ) 49 | ) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /gradle/plugins/src/main/kotlin/MetadataTask.kt: -------------------------------------------------------------------------------- 1 | import org.gradle.api.DefaultTask 2 | import org.gradle.api.file.DirectoryProperty 3 | import org.gradle.api.provider.MapProperty 4 | import org.gradle.api.provider.ProviderFactory 5 | import org.gradle.api.tasks.Input 6 | import org.gradle.api.tasks.OutputDirectory 7 | import org.gradle.api.tasks.TaskAction 8 | import javax.inject.Inject 9 | 10 | abstract class MetadataTask : DefaultTask() { 11 | 12 | @get:Input 13 | abstract val files: MapProperty 14 | 15 | @get:OutputDirectory 16 | abstract val outputDir: DirectoryProperty 17 | 18 | @get:Inject 19 | protected abstract val providers: ProviderFactory 20 | 21 | fun file(fileName: String, content: String) { 22 | files.put(fileName, content) 23 | } 24 | 25 | fun file(fileName: String, content: () -> String) { 26 | files.put(fileName, providers.provider(content)) 27 | } 28 | 29 | @TaskAction 30 | protected fun writeFiles() { 31 | val dir = outputDir.get().asFile 32 | for ((fileName, content) in files.get()) { 33 | dir.resolve(fileName).writeText(content) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /gradle/plugins/src/main/kotlin/PluginVersions.kt: -------------------------------------------------------------------------------- 1 | import org.gradle.api.GradleException 2 | import java.util.regex.Pattern 3 | 4 | object PluginVersions { 5 | /** 6 | * Increments the last integer within the given string. 7 | */ 8 | @JvmStatic 9 | fun increment(previous: String): String { 10 | val matcher = Pattern.compile("(.*\\D)(\\d+)(\\D*)").matcher(previous) 11 | if (matcher.matches()) { 12 | val incrementedNumber = Integer.parseInt(matcher.group(2)) + 1 13 | return matcher.group(1) + incrementedNumber + matcher.group(3) 14 | } else { 15 | throw GradleException("Unsupported version: $previous") 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /gradle/plugins/src/main/kotlin/local.bump-version.gradle.kts: -------------------------------------------------------------------------------- 1 | val VERSION_PROPERTY = "pluginVersion" 2 | 3 | tasks.register("bumpVersion") { 4 | description = "Bumps the version of the project" 5 | oldValue = providers.gradleProperty(VERSION_PROPERTY) 6 | newValue = oldValue.map { PluginVersions.increment(it) } 7 | propertyName = VERSION_PROPERTY 8 | dependsOn("patchChangelog") 9 | } 10 | 11 | tasks.named("patchChangelog") { 12 | // GitHub seems to use CRLF as line feeds. 13 | // We have to replace them to avoid files with mixed line endings. 14 | doFirst { 15 | val releaseNote = property("releaseNote") 16 | if (releaseNote is String) { 17 | setProperty("releaseNote", releaseNote.replace("\r\n", "\n")) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NixOS/nix-idea/511fa35445ba35078beb83496d9c0795a6664ba3/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | includeBuild("gradle/plugins") 3 | } 4 | 5 | rootProject.name = "NixIDEA" 6 | 7 | enableFeaturePreview("STABLE_CONFIGURATION_CACHE") 8 | -------------------------------------------------------------------------------- /src/main/assembly/nix-idea.xml: -------------------------------------------------------------------------------- 1 | 3 | ${project.name}-plugin 4 | true 5 | 6 | zip 7 | 8 | 9 | 10 | /lib 11 | 12 | *:jar:* 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/file/NixFile.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.file; 2 | 3 | import com.intellij.extapi.psi.PsiFileBase; 4 | import com.intellij.openapi.fileTypes.FileType; 5 | import com.intellij.psi.FileViewProvider; 6 | import org.nixos.idea.lang.NixLanguage; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import javax.swing.*; 10 | 11 | public class NixFile extends PsiFileBase { 12 | public NixFile(@NotNull FileViewProvider viewProvider) { 13 | super(viewProvider, NixLanguage.INSTANCE); 14 | } 15 | 16 | @NotNull 17 | @Override 18 | public FileType getFileType() { 19 | return NixFileType.INSTANCE; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return "Nix File"; 25 | } 26 | 27 | @Override 28 | public Icon getIcon(int flags) { 29 | return super.getIcon(flags); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/file/NixFileType.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.file; 2 | 3 | import com.intellij.openapi.fileTypes.LanguageFileType; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | import org.nixos.idea.icon.NixIcons; 7 | import org.nixos.idea.lang.NixLanguage; 8 | 9 | import javax.swing.Icon; 10 | 11 | public class NixFileType extends LanguageFileType { 12 | 13 | public static final NixFileType INSTANCE = new NixFileType(); 14 | 15 | private NixFileType() { 16 | super(NixLanguage.INSTANCE); 17 | } 18 | 19 | @NotNull 20 | @Override 21 | public String getName() { 22 | return "Nix"; 23 | } 24 | 25 | @NotNull 26 | @Override 27 | public String getDescription() { 28 | return "Nix language"; 29 | } 30 | 31 | @NotNull 32 | @Override 33 | public String getDefaultExtension() { 34 | return "nix"; 35 | } 36 | 37 | @Nullable 38 | @Override 39 | public Icon getIcon() { 40 | return NixIcons.FILE; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/icon/NixIcons.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.icon; 2 | 3 | import com.intellij.openapi.util.IconLoader; 4 | 5 | import javax.swing.*; 6 | 7 | public class NixIcons { 8 | 9 | // Documentation 10 | // -> https://plugins.jetbrains.com/docs/intellij/icons.html 11 | // Design Guide 12 | // -> https://jetbrains.design/intellij/principles/icons/ 13 | 14 | private static final Icon SNOWFLAKE = IconLoader.getIcon("/icons/nixSnowflake.svg", NixIcons.class); 15 | public static final Icon FILE = SNOWFLAKE; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/imports/NixFilePathReferenceContributor.kt: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.imports 2 | 3 | import com.intellij.codeInsight.lookup.LookupElement 4 | import com.intellij.openapi.util.TextRange 5 | import com.intellij.openapi.util.io.FileUtil 6 | import com.intellij.openapi.vfs.LocalFileSystem 7 | import com.intellij.openapi.vfs.VirtualFile 8 | import com.intellij.openapi.vfs.VirtualFileSystem 9 | import com.intellij.patterns.PlatformPatterns 10 | import com.intellij.psi.PsiElement 11 | import com.intellij.psi.PsiManager 12 | import com.intellij.psi.PsiReference 13 | import com.intellij.psi.PsiReferenceBase 14 | import com.intellij.psi.PsiReferenceContributor 15 | import com.intellij.psi.PsiReferenceProvider 16 | import com.intellij.psi.PsiReferenceRegistrar 17 | import com.intellij.util.ProcessingContext 18 | import org.nixos.idea.psi.impl.NixExprStdPathMixin 19 | 20 | class NixFilePathReferenceContributor: PsiReferenceContributor() { 21 | override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { 22 | registrar.registerReferenceProvider( 23 | PlatformPatterns.psiElement(NixExprStdPathMixin::class.java), 24 | object : PsiReferenceProvider() { 25 | override fun getReferencesByElement( 26 | element: PsiElement, 27 | context: ProcessingContext 28 | ): Array { 29 | val it = element as? NixExprStdPathMixin ?: return emptyArray() 30 | return arrayOf(NixImportReferenceImpl(it)) 31 | } 32 | } 33 | ) 34 | } 35 | } 36 | 37 | private class NixImportReferenceImpl(key: NixExprStdPathMixin) : PsiReferenceBase(key) { 38 | override fun resolve(): PsiElement? { 39 | val path = element.containingFile.parent?.virtualFile?.path ?: return null 40 | val fs = LocalFileSystem.getInstance() 41 | val file = resolvePath(fs, path, element.text) ?: return null 42 | 43 | val project = element.project 44 | val psiFile = PsiManager.getInstance(project).findFile(file) 45 | 46 | return psiFile 47 | } 48 | 49 | override fun getVariants(): Array = LookupElement.EMPTY_ARRAY 50 | 51 | override fun calculateDefaultRangeInElement(): TextRange = TextRange.from(0, element.textLength) 52 | } 53 | 54 | private fun resolvePath(fs: VirtualFileSystem, cwd: String, target: String): VirtualFile? { 55 | val resolved = FileUtil.join(cwd, target) 56 | val resolvedFile = fs.findFileByPath(resolved) ?: return null 57 | 58 | if (resolvedFile.isDirectory) { 59 | return resolvedFile.findChild("default.nix") 60 | } 61 | 62 | return resolvedFile 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/NixBraceMatcher.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang; 2 | 3 | import com.intellij.lang.BracePair; 4 | import com.intellij.lang.PairedBraceMatcher; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiFile; 7 | import com.intellij.psi.tree.IElementType; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | import org.nixos.idea.psi.NixTypes; 11 | 12 | public class NixBraceMatcher implements PairedBraceMatcher { 13 | // Grammar-Kit uses the first pair of this array to guide the error recovery 14 | // (even when structural is set to false). Since the lexer tracks curly 15 | // braces for its state transitions, the curly braces must be on top to keep 16 | // the state of parser and lexer consistent. See 17 | // https://intellij-support.jetbrains.com/hc/en-us/community/posts/360010379000 18 | public static final BracePair[] PAIRS = new BracePair[] { 19 | new BracePair(NixTypes.LCURLY,NixTypes.RCURLY,true), 20 | new BracePair(NixTypes.LBRAC,NixTypes.RBRAC,false), 21 | new BracePair(NixTypes.LPAREN,NixTypes.RPAREN,false), 22 | new BracePair(NixTypes.IND_STRING_OPEN,NixTypes.IND_STRING_CLOSE,false), 23 | new BracePair(NixTypes.STRING_OPEN,NixTypes.STRING_CLOSE,false) 24 | }; 25 | 26 | @Override 27 | public BracePair @NotNull [] getPairs() { 28 | return PAIRS; 29 | } 30 | 31 | @Override 32 | public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType lbraceType, @Nullable IElementType contextType) { 33 | return true; 34 | } 35 | 36 | @Override 37 | public int getCodeConstructStart(PsiFile file, int openingBraceOffset) { 38 | PsiElement openingBrace = file.findElementAt(openingBraceOffset); 39 | if (openingBrace != null && openingBrace.getNode().getElementType() == NixTypes.LCURLY) { 40 | PsiElement previousToken = openingBrace.getPrevSibling(); 41 | if (previousToken != null && previousToken.getNode().getElementType() == NixTypes.DOLLAR) { 42 | return openingBraceOffset - 1; 43 | } 44 | else { 45 | return openingBraceOffset; 46 | } 47 | } 48 | else { 49 | return openingBraceOffset; 50 | } 51 | } 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/NixCommenter.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang; 2 | 3 | import com.intellij.lang.Commenter; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | public class NixCommenter implements Commenter { 7 | @Override 8 | public @Nullable String getLineCommentPrefix() { 9 | return "#"; 10 | } 11 | 12 | @Override 13 | public @Nullable String getBlockCommentPrefix() { 14 | return "/*"; 15 | } 16 | 17 | @Override 18 | public @Nullable String getBlockCommentSuffix() { 19 | return "*/"; 20 | } 21 | 22 | @Override 23 | public @Nullable String getCommentedBlockCommentPrefix() { 24 | return null; 25 | } 26 | 27 | @Override 28 | public @Nullable String getCommentedBlockCommentSuffix() { 29 | return null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/NixLanguage.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang; 2 | 3 | import com.intellij.lang.Language; 4 | 5 | public class NixLanguage extends Language { 6 | public static final NixLanguage INSTANCE = new NixLanguage(); 7 | public static final String NOTIFICATION_GROUP_ID = "NixIDEA"; 8 | 9 | private NixLanguage() { 10 | super("Nix"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/NixLexer.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang; 2 | 3 | import com.intellij.lexer.FlexAdapter; 4 | 5 | public class NixLexer extends FlexAdapter { 6 | // todo: Implement RestartableLexer when it becomes non-experimental. See 7 | // https://intellij-support.jetbrains.com/hc/en-us/community/posts/360010305800/comments/360002861979 8 | 9 | public NixLexer() { 10 | super(new _NixLexer(null) { 11 | @Override 12 | public void reset(CharSequence buffer, int start, int end, int initialState) { 13 | onReset(); 14 | super.reset(buffer, start, end, initialState); 15 | } 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/NixMoveElementLeftRightHandler.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang; 2 | 3 | import com.intellij.codeInsight.editorActions.moveLeftRight.MoveElementLeftRightHandler; 4 | import com.intellij.psi.PsiElement; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.nixos.idea.psi.NixBindInherit; 7 | import org.nixos.idea.psi.NixExprApp; 8 | import org.nixos.idea.psi.NixExprAttrs; 9 | import org.nixos.idea.psi.NixExprLambda; 10 | import org.nixos.idea.psi.NixExprLet; 11 | import org.nixos.idea.psi.NixExprList; 12 | import org.nixos.idea.psi.NixFormals; 13 | import org.nixos.idea.psi.NixPsiUtil; 14 | 15 | import java.util.Collection; 16 | 17 | public final class NixMoveElementLeftRightHandler extends MoveElementLeftRightHandler { 18 | @Override 19 | public PsiElement @NotNull [] getMovableSubElements(@NotNull PsiElement element) { 20 | if (element instanceof NixExprList list) { 21 | return asArray(list.getItems()); 22 | } else if (element instanceof NixBindInherit inherit) { 23 | return asArray(inherit.getAttributes()); 24 | } else if (element instanceof NixExprAttrs attrs) { 25 | return asArray(attrs.getBindList()); 26 | } else if (element instanceof NixExprLet let) { 27 | return asArray(let.getBindList()); 28 | } else if (element instanceof NixExprLambda lambda) { 29 | return new PsiElement[]{lambda.getArgument(), lambda.getFormals()}; 30 | } else if (element instanceof NixFormals formals) { 31 | return asArray(formals.getFormalList()); 32 | } else if (element instanceof NixExprApp app) { 33 | return asArray(NixPsiUtil.getArguments(app)); 34 | } else { 35 | return PsiElement.EMPTY_ARRAY; 36 | } 37 | } 38 | 39 | private PsiElement @NotNull [] asArray(@NotNull Collection items) { 40 | return items.toArray(PsiElement[]::new); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/NixParserDefinition.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.lang.ParserDefinition; 5 | import com.intellij.lang.PsiParser; 6 | import com.intellij.lexer.Lexer; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.psi.FileViewProvider; 9 | import com.intellij.psi.PsiElement; 10 | import com.intellij.psi.PsiFile; 11 | import com.intellij.psi.tree.IElementType; 12 | import com.intellij.psi.tree.IFileElementType; 13 | import com.intellij.psi.tree.TokenSet; 14 | import org.jetbrains.annotations.NotNull; 15 | import org.jetbrains.annotations.Nullable; 16 | import org.nixos.idea.file.NixFile; 17 | import org.nixos.idea.psi.NixTokenSets; 18 | import org.nixos.idea.psi.NixTokenType; 19 | import org.nixos.idea.psi.NixTypes; 20 | 21 | public class NixParserDefinition implements ParserDefinition { 22 | 23 | public static final IFileElementType FILE = new IFileElementType(NixLanguage.INSTANCE); 24 | 25 | @Override 26 | public @NotNull Lexer createLexer(Project project) { 27 | return new NixLexer(); 28 | } 29 | 30 | @Override 31 | public @NotNull TokenSet getWhitespaceTokens() { 32 | return NixTokenSets.WHITE_SPACES; 33 | } 34 | 35 | @Override 36 | public @NotNull TokenSet getCommentTokens() { 37 | return NixTokenSets.COMMENTS; 38 | } 39 | 40 | @Override 41 | public @NotNull TokenSet getStringLiteralElements() { 42 | return NixTokenSets.STRING_LITERALS; 43 | } 44 | 45 | @Override 46 | public @NotNull PsiParser createParser(final Project project) { 47 | return new NixParser(); 48 | } 49 | 50 | @Override 51 | public @NotNull IFileElementType getFileNodeType() { 52 | return FILE; 53 | } 54 | 55 | @Override 56 | public @NotNull PsiFile createFile(@NotNull FileViewProvider viewProvider) { 57 | return new NixFile(viewProvider); 58 | } 59 | 60 | @Override 61 | public @NotNull SpaceRequirements spaceExistenceTypeBetweenTokens(ASTNode left, ASTNode right) { 62 | NixTokenType leftType = asNixTokenType(left.getElementType()); 63 | NixTokenType rightType = asNixTokenType(right.getElementType()); 64 | if (leftType == NixTypes.SCOMMENT) { 65 | return SpaceRequirements.MUST_LINE_BREAK; 66 | } 67 | if (leftType == NixTypes.DOLLAR && rightType == NixTypes.LCURLY) { 68 | return SpaceRequirements.MUST_NOT; 69 | } 70 | else if (leftType == NixTypes.PATH_SEGMENT) { 71 | // path segment, antiquotation or PATH_END on the right 72 | return SpaceRequirements.MUST_NOT; 73 | } 74 | else if (rightType == NixTypes.PATH_END) { 75 | // path segment or antiquotation on the left 76 | return SpaceRequirements.MUST_NOT; 77 | } 78 | else if (NixTokenSets.MIGHT_COLLAPSE_WITH_ID.contains(leftType) && 79 | NixTokenSets.MIGHT_COLLAPSE_WITH_ID.contains(rightType)) { 80 | return SpaceRequirements.MUST; 81 | } 82 | else { 83 | return SpaceRequirements.MAY; 84 | } 85 | } 86 | 87 | @NotNull 88 | @Override 89 | public PsiElement createElement(ASTNode node) { 90 | return NixTypes.Factory.createElement(node); 91 | } 92 | 93 | private static @Nullable NixTokenType asNixTokenType(IElementType elementType) { 94 | return elementType instanceof NixTokenType ? (NixTokenType) elementType : null; 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/NixSpellcheckingStrategy.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.spellchecker.inspections.IdentifierSplitter; 5 | import com.intellij.spellchecker.tokenizer.SpellcheckingStrategy; 6 | import com.intellij.spellchecker.tokenizer.Tokenizer; 7 | import com.intellij.spellchecker.tokenizer.TokenizerBase; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.nixos.idea.psi.NixIdentifier; 10 | import org.nixos.idea.psi.NixPsiUtil; 11 | import org.nixos.idea.psi.NixStringText; 12 | 13 | /** 14 | * Enables spell checking for Nix files. 15 | * 16 | * @see Spell Checking Documentation 17 | * @see Spell Checking Tutorial 18 | */ 19 | public final class NixSpellcheckingStrategy extends SpellcheckingStrategy { 20 | 21 | // TODO: Implement SuppressibleSpellcheckingStrategy 22 | // https://plugins.jetbrains.com/docs/intellij/spell-checking.html#suppressing-spellchecking 23 | // TODO: Suggest rename-refactoring for identifiers (when rename refactoring is supported) 24 | 25 | private static final Tokenizer IDENTIFIER_TOKENIZER = TokenizerBase.create(IdentifierSplitter.getInstance()); 26 | 27 | @Override 28 | public @NotNull Tokenizer getTokenizer(PsiElement element) { 29 | if (element instanceof NixIdentifier identifier && NixPsiUtil.isDeclaration(identifier)) { 30 | return IDENTIFIER_TOKENIZER; 31 | } 32 | if (element instanceof NixStringText) { 33 | return TEXT_TOKENIZER; 34 | } 35 | return super.getTokenizer(element); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/highlighter/NixHighlightVisitor.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.highlighter; 2 | 3 | import com.intellij.codeInsight.daemon.impl.HighlightInfo; 4 | import com.intellij.codeInsight.daemon.impl.HighlightInfoType; 5 | import com.intellij.codeInsight.daemon.impl.HighlightVisitor; 6 | import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiFile; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | public final class NixHighlightVisitor implements HighlightVisitor { 13 | 14 | private HighlightInfoHolder myHolder; 15 | private Delegate myDelegate; 16 | 17 | @Override 18 | public boolean suitableForFile(@NotNull PsiFile file) { 19 | return NixHighlightVisitorDelegate.suitableForFile(file); 20 | } 21 | 22 | @Override 23 | public void visit(@NotNull PsiElement element) { 24 | myDelegate.visit(element); 25 | } 26 | 27 | @Override 28 | public boolean analyze(@NotNull PsiFile file, boolean updateWholeFile, @NotNull HighlightInfoHolder holder, @NotNull Runnable action) { 29 | try { 30 | myHolder = holder; 31 | myDelegate = new Delegate(); 32 | action.run(); 33 | } finally { 34 | myHolder = null; 35 | myDelegate = null; 36 | } 37 | return true; 38 | } 39 | 40 | @Override 41 | @SuppressWarnings("MethodDoesntCallSuperMethod") 42 | public @NotNull HighlightVisitor clone() { 43 | return new NixHighlightVisitor(); 44 | } 45 | 46 | private final class Delegate extends NixHighlightVisitorDelegate { 47 | @Override 48 | void highlight(@NotNull PsiElement element, @Nullable PsiElement source, @NotNull String attrPath, @Nullable HighlightInfoType type) { 49 | if (type != null) { 50 | myHolder.add(HighlightInfo.newHighlightInfo(type) 51 | .range(element) 52 | .create()); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/highlighter/NixRainbowVisitor.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.highlighter; 2 | 3 | import com.intellij.codeInsight.daemon.RainbowVisitor; 4 | import com.intellij.codeInsight.daemon.impl.HighlightInfoType; 5 | import com.intellij.codeInsight.daemon.impl.HighlightVisitor; 6 | import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder; 7 | import com.intellij.openapi.editor.colors.TextAttributesKey; 8 | import com.intellij.psi.PsiElement; 9 | import com.intellij.psi.PsiFile; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | import java.util.List; 14 | 15 | public final class NixRainbowVisitor extends RainbowVisitor { 16 | 17 | public static final List RAINBOW_ATTRIBUTES = List.of( 18 | NixTextAttributes.LOCAL_VARIABLE, 19 | NixTextAttributes.PARAMETER); 20 | 21 | private Delegate myDelegate; 22 | 23 | @Override 24 | public boolean suitableForFile(@NotNull PsiFile file) { 25 | return NixHighlightVisitorDelegate.suitableForFile(file); 26 | } 27 | 28 | @Override 29 | public void visit(@NotNull PsiElement element) { 30 | myDelegate.visit(element); 31 | } 32 | 33 | @Override 34 | public boolean analyze(@NotNull PsiFile file, boolean updateWholeFile, @NotNull HighlightInfoHolder holder, @NotNull Runnable action) { 35 | myDelegate = new Delegate(file); 36 | try { 37 | return super.analyze(file, updateWholeFile, holder, action); 38 | } finally { 39 | myDelegate = null; 40 | } 41 | } 42 | 43 | @Override 44 | public @NotNull HighlightVisitor clone() { 45 | return new NixRainbowVisitor(); 46 | } 47 | 48 | private final class Delegate extends NixHighlightVisitorDelegate { 49 | private final @NotNull PsiFile file; 50 | 51 | private Delegate(@NotNull PsiFile file) { 52 | this.file = file; 53 | } 54 | 55 | @Override 56 | void highlight(@NotNull PsiElement element, @Nullable PsiElement source, @NotNull String attrPath, @Nullable HighlightInfoType type) { 57 | if (type != LITERAL && type != IMPORT && type != BUILTIN) { 58 | TextAttributesKey attributesKey = type == null ? NixTextAttributes.IDENTIFIER : type.getAttributesKey(); 59 | PsiElement context = source == null ? file : source; 60 | addInfo(getInfo(context, element, attrPath, attributesKey)); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/highlighter/NixSyntaxHighlighterFactory.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.highlighter; 2 | 3 | import com.intellij.openapi.fileTypes.SyntaxHighlighter; 4 | import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.openapi.vfs.VirtualFile; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | public class NixSyntaxHighlighterFactory extends SyntaxHighlighterFactory { 10 | @Override 11 | public @NotNull SyntaxHighlighter getSyntaxHighlighter(Project project, VirtualFile virtualFile) { 12 | return new NixSyntaxHighlighter(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/references/NixNavigationTarget.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.references; 2 | 3 | import com.intellij.model.Pointer; 4 | import com.intellij.openapi.util.TextRange; 5 | import com.intellij.platform.backend.navigation.NavigationRequest; 6 | import com.intellij.platform.backend.navigation.NavigationTarget; 7 | import com.intellij.platform.backend.presentation.TargetPresentation; 8 | import com.intellij.psi.SmartPointerManager; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | import org.jetbrains.annotations.TestOnly; 12 | import org.nixos.idea.psi.NixPsiElement; 13 | 14 | @SuppressWarnings("UnstableApiUsage") 15 | public final class NixNavigationTarget implements NavigationTarget { 16 | 17 | private final @NotNull NixPsiElement myIdentifier; 18 | private final @NotNull TargetPresentation myTargetPresentation; 19 | private @Nullable Pointer myPointer; 20 | 21 | public NixNavigationTarget(@NotNull NixPsiElement identifier, @NotNull TargetPresentation targetPresentation) { 22 | myIdentifier = identifier; 23 | myTargetPresentation = targetPresentation; 24 | } 25 | 26 | private NixNavigationTarget(@NotNull Pointer pointer, 27 | @NotNull NixPsiElement identifier, 28 | @NotNull TargetPresentation targetPresentation) { 29 | myIdentifier = identifier; 30 | myTargetPresentation = targetPresentation; 31 | myPointer = pointer; 32 | } 33 | 34 | @TestOnly 35 | TextRange getRangeInFile() { 36 | return myIdentifier.getTextRange(); 37 | } 38 | 39 | @Override 40 | public @NotNull Pointer createPointer() { 41 | if (myPointer == null) { 42 | TargetPresentation targetPresentation = myTargetPresentation; 43 | myPointer = Pointer.uroborosPointer( 44 | SmartPointerManager.createPointer(myIdentifier), 45 | (identifier, pointer) -> new NixNavigationTarget(pointer, identifier, targetPresentation)); 46 | } 47 | return myPointer; 48 | } 49 | 50 | @Override 51 | public @NotNull TargetPresentation computePresentation() { 52 | return myTargetPresentation; 53 | } 54 | 55 | @Override 56 | public @Nullable NavigationRequest navigationRequest() { 57 | return NavigationRequest.sourceNavigationRequest(myIdentifier.getContainingFile(), myIdentifier.getTextRange()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/references/NixScopeReference.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.references; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.nixos.idea.lang.references.symbol.NixSymbol; 5 | import org.nixos.idea.psi.NixPsiElement; 6 | 7 | import java.util.Collection; 8 | 9 | @SuppressWarnings("UnstableApiUsage") 10 | public final class NixScopeReference extends NixSymbolReference { 11 | 12 | public NixScopeReference(@NotNull NixPsiElement element, @NotNull NixPsiElement identifier, @NotNull String variableName) { 13 | super(element, identifier, variableName); 14 | } 15 | 16 | @Override 17 | public @NotNull Collection resolveReference() { 18 | return myElement.getScope().resolveVariable(myName); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/references/NixSymbolDeclaration.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.references; 2 | 3 | import com.intellij.model.psi.PsiSymbolDeclaration; 4 | import com.intellij.openapi.util.TextRange; 5 | import com.intellij.platform.backend.navigation.NavigationTarget; 6 | import com.intellij.platform.backend.presentation.TargetPresentation; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | import org.nixos.idea.lang.references.symbol.NixUserSymbol; 10 | import org.nixos.idea.psi.NixPsiElement; 11 | import org.nixos.idea.util.TextRangeFactory; 12 | 13 | @SuppressWarnings("UnstableApiUsage") 14 | public final class NixSymbolDeclaration implements PsiSymbolDeclaration { 15 | 16 | private final @NotNull NixPsiElement myDeclarationElement; 17 | private final @NotNull NixPsiElement myIdentifier; 18 | private final @NotNull NixUserSymbol mySymbol; 19 | private final @NotNull String myDeclarationElementName; 20 | private final @Nullable String myDeclarationElementType; 21 | 22 | public NixSymbolDeclaration(@NotNull NixPsiElement declarationElement, @NotNull NixPsiElement identifier, 23 | @NotNull NixUserSymbol symbol, 24 | @NotNull String declarationElementName, @Nullable String declarationElementType) { 25 | myDeclarationElement = declarationElement; 26 | myIdentifier = identifier; 27 | mySymbol = symbol; 28 | myDeclarationElementName = declarationElementName; 29 | myDeclarationElementType = declarationElementType; 30 | } 31 | 32 | public @NotNull NixPsiElement getIdentifier() { 33 | return myIdentifier; 34 | } 35 | 36 | public @NotNull NavigationTarget navigationTarget() { 37 | return new NixNavigationTarget(myIdentifier, TargetPresentation.builder(mySymbol.presentation()) 38 | .presentableText(myDeclarationElementName) 39 | .containerText(myDeclarationElementType) 40 | .presentation()); 41 | } 42 | 43 | @Override 44 | public @NotNull NixPsiElement getDeclaringElement() { 45 | return myDeclarationElement; 46 | } 47 | 48 | @Override 49 | public @NotNull TextRange getRangeInDeclaringElement() { 50 | return TextRangeFactory.relative(myIdentifier, myDeclarationElement); 51 | } 52 | 53 | @Override 54 | public @NotNull NixUserSymbol getSymbol() { 55 | return mySymbol; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/references/NixSymbolReference.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.references; 2 | 3 | import com.intellij.model.Symbol; 4 | import com.intellij.model.psi.PsiSymbolReference; 5 | import com.intellij.openapi.util.TextRange; 6 | import com.intellij.psi.PsiElement; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.nixos.idea.lang.references.symbol.NixSymbol; 9 | import org.nixos.idea.psi.NixPsiElement; 10 | import org.nixos.idea.util.TextRangeFactory; 11 | 12 | @SuppressWarnings("UnstableApiUsage") 13 | public abstract class NixSymbolReference implements PsiSymbolReference { 14 | 15 | protected final @NotNull NixPsiElement myElement; 16 | protected final @NotNull NixPsiElement myIdentifier; 17 | protected final @NotNull String myName; 18 | 19 | protected NixSymbolReference(@NotNull NixPsiElement element, @NotNull NixPsiElement identifier, @NotNull String name) { 20 | myElement = element; 21 | myIdentifier = identifier; 22 | myName = name; 23 | } 24 | 25 | public @NotNull NixPsiElement getIdentifier() { 26 | return myIdentifier; 27 | } 28 | 29 | @Override 30 | public @NotNull PsiElement getElement() { 31 | return myElement; 32 | } 33 | 34 | @Override 35 | public @NotNull TextRange getRangeInElement() { 36 | return TextRangeFactory.relative(myIdentifier, myElement); 37 | } 38 | 39 | @Override 40 | public boolean resolvesTo(@NotNull Symbol target) { 41 | // Check name as a shortcut to avoid resolving the reference when it cannot match anyway. 42 | return target instanceof NixSymbol t && 43 | myName.equals(t.getName()) && 44 | PsiSymbolReference.super.resolvesTo(target); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/references/NixUsage.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.references; 2 | 3 | import com.intellij.find.usages.api.PsiUsage; 4 | import com.intellij.find.usages.api.ReadWriteUsage; 5 | import com.intellij.find.usages.api.UsageAccess; 6 | import com.intellij.model.Pointer; 7 | import com.intellij.openapi.util.TextRange; 8 | import com.intellij.psi.PsiFile; 9 | import com.intellij.psi.SmartPointerManager; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | import org.nixos.idea.psi.NixPsiElement; 13 | import org.nixos.idea.settings.NixSymbolSettings; 14 | 15 | @SuppressWarnings("UnstableApiUsage") 16 | final class NixUsage implements PsiUsage, ReadWriteUsage { 17 | 18 | private final @NotNull NixPsiElement myIdentifier; 19 | private final boolean myIsDeclaration; 20 | private @Nullable Pointer myPointer; 21 | 22 | NixUsage(@NotNull NixSymbolDeclaration declaration) { 23 | myIdentifier = declaration.getIdentifier(); 24 | myIsDeclaration = true; 25 | } 26 | 27 | NixUsage(@NotNull NixSymbolReference reference) { 28 | myIdentifier = reference.getIdentifier(); 29 | myIsDeclaration = false; 30 | } 31 | 32 | private NixUsage(@NotNull Pointer pointer, @NotNull NixPsiElement identifier, boolean isDeclaration) { 33 | myIdentifier = identifier; 34 | myIsDeclaration = isDeclaration; 35 | myPointer = pointer; 36 | } 37 | 38 | @Override 39 | public @NotNull Pointer createPointer() { 40 | if (myPointer == null) { 41 | boolean isDeclaration = myIsDeclaration; 42 | myPointer = Pointer.uroborosPointer( 43 | SmartPointerManager.createPointer(myIdentifier), 44 | (identifier, pointer) -> new NixUsage(pointer, identifier, isDeclaration)); 45 | } 46 | return myPointer; 47 | } 48 | 49 | @Override 50 | public @NotNull PsiFile getFile() { 51 | return myIdentifier.getContainingFile(); 52 | } 53 | 54 | @Override 55 | public @NotNull TextRange getRange() { 56 | return myIdentifier.getTextRange(); 57 | } 58 | 59 | @Override 60 | public boolean getDeclaration() { 61 | // IDEA removes all instances which return true from the result of the usage search 62 | return !NixSymbolSettings.getInstance().getShowDeclarationsAsUsages() && myIsDeclaration; 63 | } 64 | 65 | @Override 66 | public @Nullable UsageAccess computeAccess() { 67 | return myIsDeclaration ? UsageAccess.Write : UsageAccess.Read; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/references/NixUsageSearcher.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.references; 2 | 3 | import com.intellij.find.usages.api.Usage; 4 | import com.intellij.find.usages.api.UsageSearchParameters; 5 | import com.intellij.find.usages.api.UsageSearcher; 6 | import com.intellij.model.search.LeafOccurrence; 7 | import com.intellij.model.search.LeafOccurrenceMapper; 8 | import com.intellij.model.search.SearchContext; 9 | import com.intellij.model.search.SearchService; 10 | import com.intellij.psi.PsiElement; 11 | import com.intellij.util.Query; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | import org.nixos.idea.lang.NixLanguage; 15 | import org.nixos.idea.lang.references.symbol.NixSymbol; 16 | import org.nixos.idea.lang.references.symbol.NixUserSymbol; 17 | import org.nixos.idea.psi.NixPsiElement; 18 | import org.nixos.idea.settings.NixSymbolSettings; 19 | 20 | import java.util.Collection; 21 | import java.util.List; 22 | 23 | @SuppressWarnings("UnstableApiUsage") 24 | public final class NixUsageSearcher implements UsageSearcher, LeafOccurrenceMapper.Parameterized { 25 | 26 | @Override 27 | public @NotNull Collection collectImmediateResults(@NotNull UsageSearchParameters parameters) { 28 | if (!NixSymbolSettings.getInstance().getEnabled()) { 29 | return List.of(); 30 | } else if (parameters.getTarget() instanceof NixUserSymbol symbol) { 31 | return symbol.getDeclarations().stream().map(NixUsage::new).toList(); 32 | } else { 33 | return List.of(); 34 | } 35 | } 36 | 37 | @Override 38 | public @Nullable Query collectSearchRequest(@NotNull UsageSearchParameters parameters) { 39 | if (!NixSymbolSettings.getInstance().getEnabled()) { 40 | return null; 41 | } else if (parameters.getTarget() instanceof NixSymbol symbol) { 42 | String name = symbol.getName(); 43 | return SearchService.getInstance() 44 | .searchWord(parameters.getProject(), name) 45 | .inContexts(SearchContext.IN_CODE_HOSTS, SearchContext.IN_CODE) 46 | .inScope(parameters.getSearchScope()) 47 | .inFilesWithLanguage(NixLanguage.INSTANCE) 48 | .buildQuery(LeafOccurrenceMapper.withPointer(symbol.createPointer(), this)); 49 | } else { 50 | return null; 51 | } 52 | } 53 | 54 | @Override 55 | public @NotNull Collection mapOccurrence(@NotNull NixSymbol symbol, @NotNull LeafOccurrence occurrence) { 56 | for (PsiElement element = occurrence.getStart(); element != null && element != occurrence.getScope(); element = element.getParent()) { 57 | if (element instanceof NixPsiElement nixElement) { 58 | List usages = nixElement.getOwnReferences().stream() 59 | .filter(reference -> reference.resolvesTo(symbol)) 60 | .map(NixUsage::new) 61 | .toList(); 62 | if (!usages.isEmpty()) { 63 | return usages; 64 | } 65 | } 66 | } 67 | return List.of(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/references/symbol/Commons.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.references.symbol; 2 | 3 | import com.intellij.openapi.editor.colors.EditorColorsManager; 4 | import com.intellij.openapi.editor.colors.EditorColorsScheme; 5 | import com.intellij.openapi.editor.colors.TextAttributesKey; 6 | import com.intellij.platform.backend.presentation.TargetPresentation; 7 | import com.intellij.platform.backend.presentation.TargetPresentationBuilder; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import javax.swing.Icon; 11 | 12 | @SuppressWarnings("UnstableApiUsage") 13 | final class Commons { 14 | private Commons() {} // Cannot be instantiated 15 | 16 | static @NotNull TargetPresentationBuilder buildPresentation(@NotNull String name, @NotNull Icon icon, @NotNull TextAttributesKey textAttributesKey) { 17 | EditorColorsScheme colorsScheme = EditorColorsManager.getInstance().getSchemeForCurrentUITheme(); 18 | return TargetPresentation.builder(name) 19 | .icon(icon) 20 | .presentableTextAttributes(colorsScheme.getAttributes(textAttributesKey)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/references/symbol/NixBuiltinSymbol.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.references.symbol; 2 | 3 | import com.intellij.icons.AllIcons; 4 | import com.intellij.model.Pointer; 5 | import com.intellij.platform.backend.presentation.TargetPresentation; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.nixos.idea.lang.builtins.NixBuiltin; 8 | import org.nixos.idea.lang.highlighter.NixTextAttributes; 9 | 10 | import java.util.Objects; 11 | 12 | @SuppressWarnings("UnstableApiUsage") 13 | final class NixBuiltinSymbol extends NixSymbol 14 | implements Pointer { 15 | 16 | private final @NotNull NixBuiltin myBuiltin; 17 | 18 | NixBuiltinSymbol(@NotNull NixBuiltin builtin) { 19 | myBuiltin = builtin; 20 | } 21 | 22 | @Override 23 | public @NotNull String getName() { 24 | return myBuiltin.name(); 25 | } 26 | 27 | @Override 28 | public @NotNull Pointer createPointer() { 29 | return this; 30 | } 31 | 32 | @Override 33 | public @NotNull NixBuiltinSymbol dereference() { 34 | return this; 35 | } 36 | 37 | @Override 38 | public @NotNull TargetPresentation presentation() { 39 | return Commons.buildPresentation(myBuiltin.name(), AllIcons.Nodes.Padlock, NixTextAttributes.BUILTIN) 40 | .presentation(); 41 | } 42 | 43 | @Override 44 | public boolean equals(Object o) { 45 | if (this == o) return true; 46 | if (o == null || getClass() != o.getClass()) return false; 47 | NixBuiltinSymbol builtin = (NixBuiltinSymbol) o; 48 | return Objects.equals(myBuiltin, builtin.myBuiltin); 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | return Objects.hash(myBuiltin); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lang/references/symbol/NixSymbol.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.references.symbol; 2 | 3 | import com.intellij.find.usages.api.SearchTarget; 4 | import com.intellij.find.usages.api.UsageHandler; 5 | import com.intellij.model.Pointer; 6 | import com.intellij.model.Symbol; 7 | import org.jetbrains.annotations.Contract; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.nixos.idea.lang.builtins.NixBuiltin; 10 | 11 | @SuppressWarnings("UnstableApiUsage") 12 | public abstract sealed class NixSymbol implements Symbol, SearchTarget 13 | permits NixBuiltinSymbol, NixUserSymbol { 14 | 15 | NixSymbol() {} // Can only be implemented within this package 16 | 17 | @Contract(pure = true) 18 | public static @NotNull NixSymbol builtin(@NotNull NixBuiltin builtin) { 19 | return new NixBuiltinSymbol(builtin); 20 | } 21 | 22 | @Contract(pure = true) 23 | public abstract @NotNull String getName(); 24 | 25 | @Override 26 | public abstract @NotNull Pointer createPointer(); 27 | 28 | @Override 29 | public @NotNull UsageHandler getUsageHandler() { 30 | return UsageHandler.createEmptyUsageHandler(getName()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lsp/NixLspServerDescriptor.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lsp; 2 | 3 | import com.intellij.execution.ExecutionException; 4 | import com.intellij.execution.configurations.GeneralCommandLine; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.openapi.vfs.VirtualFile; 7 | import com.intellij.platform.lsp.api.ProjectWideLspServerDescriptor; 8 | import com.intellij.util.execution.ParametersListUtil; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.nixos.idea.file.NixFileType; 11 | 12 | import java.util.List; 13 | 14 | @SuppressWarnings("UnstableApiUsage") 15 | final class NixLspServerDescriptor extends ProjectWideLspServerDescriptor { 16 | 17 | private final String myCommand; 18 | 19 | NixLspServerDescriptor(@NotNull Project project, NixLspSettings settings) { 20 | super(project, "Nix"); 21 | myCommand = settings.getCommand(); 22 | } 23 | 24 | @Override 25 | public @NotNull GeneralCommandLine createCommandLine() throws ExecutionException { 26 | List argv = ParametersListUtil.parse(myCommand, false, true); 27 | return new GeneralCommandLine(argv); 28 | } 29 | 30 | @Override 31 | public boolean isSupportedFile(@NotNull VirtualFile virtualFile) { 32 | return virtualFile.getFileType() == NixFileType.INSTANCE; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lsp/NixLspServerSupportProvider.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lsp; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.vfs.VirtualFile; 5 | import com.intellij.platform.lsp.api.LspServer; 6 | import com.intellij.platform.lsp.api.LspServerSupportProvider; 7 | import com.intellij.platform.lsp.api.lsWidget.LspServerWidgetItem; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | import org.nixos.idea.file.NixFileType; 11 | import org.nixos.idea.icon.NixIcons; 12 | 13 | @SuppressWarnings("UnstableApiUsage") 14 | public final class NixLspServerSupportProvider implements LspServerSupportProvider { 15 | @Override 16 | public void fileOpened(@NotNull Project project, @NotNull VirtualFile virtualFile, @NotNull LspServerStarter lspServerStarter) { 17 | if (virtualFile.getFileType() == NixFileType.INSTANCE) { 18 | NixLspSettings settings = NixLspSettings.getInstance(); 19 | if (settings.isEnabled()) { 20 | lspServerStarter.ensureServerStarted(new NixLspServerDescriptor(project, settings)); 21 | } 22 | } 23 | } 24 | 25 | @Override 26 | public @NotNull LspServerWidgetItem createLspServerWidgetItem(@NotNull LspServer lspServer, @Nullable VirtualFile currentFile) { 27 | return new LspServerWidgetItem(lspServer, currentFile, NixIcons.FILE, NixLspSettingsConfigurable.class); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lsp/NixLspSettings.kt: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lsp 2 | 3 | import com.intellij.openapi.application.ApplicationManager 4 | import com.intellij.openapi.components.BaseState 5 | import com.intellij.openapi.components.RoamingType 6 | import com.intellij.openapi.components.SimplePersistentStateComponent 7 | import com.intellij.openapi.components.State 8 | import com.intellij.openapi.components.Storage 9 | import org.nixos.idea.settings.NixStoragePaths 10 | import org.nixos.idea.settings.SimplePersistentStateComponentHelper.delegate 11 | import java.util.ArrayDeque 12 | import java.util.Collections 13 | import java.util.Deque 14 | 15 | @State(name = "NixLspSettings", storages = [Storage(value = NixStoragePaths.TOOLS, roamingType = RoamingType.LOCAL)]) 16 | class NixLspSettings : SimplePersistentStateComponent(State()) { 17 | 18 | class State : BaseState() { 19 | var enabled by property(false) 20 | var command by string() 21 | var history: Deque by property(ArrayDeque(), { it.isEmpty() }) 22 | } 23 | 24 | var isEnabled: Boolean by delegate(State::enabled) 25 | var command: String by delegate(State::command, State::history) 26 | val commandHistory: Collection 27 | get() = Collections.unmodifiableCollection(state.history) 28 | 29 | companion object { 30 | @JvmStatic 31 | fun getInstance(): NixLspSettings { 32 | return ApplicationManager.getApplication().getService(NixLspSettings::class.java) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/lsp/NixLspSettingsConfigurable.kt: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lsp 2 | 3 | import com.intellij.openapi.options.BoundSearchableConfigurable 4 | import com.intellij.openapi.options.Configurable 5 | import com.intellij.openapi.project.ProjectManager 6 | import com.intellij.platform.lsp.api.LspServerManager 7 | import com.intellij.ui.RawCommandLineEditor 8 | import com.intellij.ui.components.JBCheckBox 9 | import com.intellij.ui.dsl.builder.AlignX 10 | import com.intellij.ui.dsl.builder.Cell 11 | import com.intellij.ui.dsl.builder.bindSelected 12 | import com.intellij.ui.dsl.builder.panel 13 | import com.intellij.ui.dsl.builder.selected 14 | import org.nixos.idea.settings.ui.CommandSuggestionsPopup 15 | import org.nixos.idea.settings.ui.UiDslExtensions.bindText 16 | import org.nixos.idea.settings.ui.UiDslExtensions.placeholderText 17 | import org.nixos.idea.settings.ui.UiDslExtensions.suggestionsPopup 18 | import org.nixos.idea.settings.ui.UiDslExtensions.validateOnReset 19 | import org.nixos.idea.settings.ui.UiDslExtensions.validateWhenTextChanged 20 | import org.nixos.idea.settings.ui.UiDslExtensions.warnOnInput 21 | 22 | class NixLspSettingsConfigurable : 23 | BoundSearchableConfigurable("Language Server (LSP)", "org.nixos.idea.lsp.NixLspSettingsConfigurable"), 24 | Configurable.Beta { 25 | 26 | override fun createPanel() = panel { 27 | val settings = NixLspSettings.getInstance() 28 | lateinit var enabledCheckBox: Cell 29 | row { 30 | enabledCheckBox = checkBox("Enable language server") 31 | .bindSelected(settings::isEnabled) 32 | } 33 | group("Language Server Configuration") { 34 | row("Command:") { 35 | cell(RawCommandLineEditor()) 36 | .bindText(settings::command) 37 | .placeholderText("Command to start Language Server") 38 | .suggestionsPopup(settings.commandHistory, BUILTIN_SUGGESTIONS) 39 | .align(AlignX.FILL) 40 | .validateOnReset() 41 | .validateWhenTextChanged() 42 | .warnOnInput("You have to specify the command to start the Language Server") { 43 | it.text.isNullOrBlank() 44 | } 45 | } 46 | }.enabledIf(enabledCheckBox.selected) 47 | } 48 | 49 | @Suppress("UnstableApiUsage") 50 | override fun apply() { 51 | super.apply() 52 | reset() // Update UI components to use normalized property values 53 | for (project in ProjectManager.getInstance().openProjects) { 54 | LspServerManager.getInstance(project).stopAndRestartIfNeeded(NixLspServerSupportProvider::class.java) 55 | } 56 | } 57 | } 58 | 59 | private val BUILTIN_SUGGESTIONS: List = listOf( 60 | CommandSuggestionsPopup.Suggestion.builtin( 61 | "Use nil from nixpkgs", 62 | "nix --extra-experimental-features \"nix-command flakes\" run nixpkgs#nil" 63 | ), 64 | CommandSuggestionsPopup.Suggestion.builtin( 65 | "Use nixd from nixpkgs", 66 | "nix --extra-experimental-features \"nix-command flakes\" run nixpkgs#nixd" 67 | ) 68 | ) 69 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/psi/NixDeclarationHost.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.psi; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | import org.nixos.idea.lang.references.NixSymbolDeclaration; 6 | import org.nixos.idea.lang.references.symbol.NixUserSymbol; 7 | 8 | import java.util.Collection; 9 | import java.util.List; 10 | 11 | /** 12 | * An element which may contain declarations. 13 | * There are two types of declaration hosts: 14 | *
    15 | *
  1. Elements which declare variables. 16 | * The declared variables are accessible in the subtree of this element. 17 | *
      18 | *
    • {@link NixExprLet} 19 | *
    • {@link NixExprLambda} 20 | *
    • {@link NixExprAttrs} if {@linkplain NixPsiUtil#isRecursive(NixExprAttrs) recursive} 21 | *
    22 | *
  2. Elements which declare attributes. 23 | * The attributes are accessible via the result of this expression. 24 | *
      25 | *
    • {@link NixExprAttrs} if not a {@linkplain NixPsiUtil#isLegacyLet(NixExprAttrs) legacy let expression} 26 | *
    27 | *
28 | * These two cases are only implemented as one interface because 29 | * the implementation is effectively the same in case of {@link NixExprLet} and {@link NixExprAttrs}. 30 | */ 31 | public interface NixDeclarationHost extends NixPsiElement { 32 | /** 33 | * Whether declarations of this element may be accessible as variables. 34 | * If this method returns {@code true}, {@link #getSymbolForScope(String)} may be called to resolve a variable. 35 | * 36 | * @return {@code true} if the declarations shall be added to the scope. 37 | */ 38 | boolean isDeclaringVariables(); 39 | 40 | /** 41 | * Returns the symbol for the given variable name. 42 | * Must not be called when {@link #isDeclaringVariables()} returns {@code false}. 43 | * Symbols exposed via this method become available from {@link #getScope()} in all children. 44 | * The method returns {@code null} if no variable with the given name is declared from this element. 45 | * 46 | * @param variableName The name of the variable. 47 | * @return The symbol representing the variable, or {@code null}. 48 | */ 49 | @Nullable NixUserSymbol getSymbolForScope(@NotNull String variableName); 50 | 51 | @Nullable NixUserSymbol getSymbol(@NotNull List attributePath); 52 | 53 | @NotNull Collection getDeclarations(@NotNull List attributePath); 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/psi/NixElementType.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.psi; 2 | 3 | import org.nixos.idea.lang.NixLanguage; 4 | import com.intellij.psi.tree.IElementType; 5 | import org.jetbrains.annotations.NonNls; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public class NixElementType extends IElementType { 9 | 10 | public NixElementType(@NotNull @NonNls String debugName) { 11 | super(debugName, NixLanguage.INSTANCE); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/psi/NixPsiElement.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.psi; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.nixos.idea.lang.references.NixSymbolDeclaration; 6 | import org.nixos.idea.lang.references.NixSymbolReference; 7 | import org.nixos.idea.lang.references.Scope; 8 | 9 | import java.util.Collection; 10 | 11 | public interface NixPsiElement extends PsiElement { 12 | 13 | @NotNull Scope getScope(); 14 | 15 | @Override 16 | @SuppressWarnings("UnstableApiUsage") 17 | @NotNull Collection getOwnDeclarations(); 18 | 19 | @Override 20 | @SuppressWarnings("UnstableApiUsage") 21 | @NotNull Collection getOwnReferences(); 22 | 23 | T accept(@NotNull NixElementVisitor visitor); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/psi/NixTokenSets.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.psi; 2 | 3 | import com.intellij.psi.TokenType; 4 | import com.intellij.psi.tree.TokenSet; 5 | 6 | public final class NixTokenSets { 7 | 8 | /** All tokens representing whitespaces. */ 9 | public static final TokenSet WHITE_SPACES = TokenSet.create(TokenType.WHITE_SPACE); 10 | 11 | /** All tokens representing comments. */ 12 | public static final TokenSet COMMENTS = TokenSet.create(NixTypes.SCOMMENT, NixTypes.MCOMMENT); 13 | 14 | /** Elements representing string literals. Note that these types are used for non-leaf elements, they don't represent tokens. */ 15 | public static final TokenSet STRING_LITERALS = TokenSet.create(NixTypes.STD_STRING, NixTypes.IND_STRING); 16 | 17 | /** All token types which represent a keyword. */ 18 | public static final TokenSet KEYWORDS = TokenSet.create( 19 | NixTypes.IF, 20 | NixTypes.THEN, 21 | NixTypes.ELSE, 22 | NixTypes.ASSERT, 23 | NixTypes.WITH, 24 | NixTypes.LET, 25 | NixTypes.IN, 26 | NixTypes.REC, 27 | NixTypes.INHERIT, 28 | NixTypes.OR_KW); 29 | 30 | /** All tokens representing opening quotes. */ 31 | public static final TokenSet OPENING_QUOTES = TokenSet.create(NixTypes.STRING_OPEN, NixTypes.IND_STRING_OPEN); 32 | /** All tokens representing closing quotes. */ 33 | public static final TokenSet CLOSING_QUOTES = TokenSet.create(NixTypes.STRING_CLOSE, NixTypes.IND_STRING_CLOSE); 34 | /** All tokens representing text inside a string. */ 35 | public static final TokenSet STRING_CONTENT = TokenSet.create(NixTypes.STR, NixTypes.STR_ESCAPE, NixTypes.IND_STR, NixTypes.IND_STR_ESCAPE); 36 | /** All tokens representing any part of a string, except interpolations. */ 37 | public static final TokenSet STRING_ANY = TokenSet.orSet(CLOSING_QUOTES, OPENING_QUOTES, STRING_CONTENT); 38 | 39 | /** Tokens would collapse if they were not separated by whitespace. */ 40 | public static final TokenSet MIGHT_COLLAPSE_WITH_ID = TokenSet.orSet( 41 | KEYWORDS, 42 | TokenSet.create( 43 | NixTypes.ID, 44 | NixTypes.INT, 45 | NixTypes.FLOAT, 46 | NixTypes.SPATH, 47 | NixTypes.PATH_SEGMENT, 48 | NixTypes.PATH_END, 49 | NixTypes.URI)); 50 | 51 | private NixTokenSets() {} // Cannot be instantiated 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/psi/NixTokenType.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.psi; 2 | 3 | import com.intellij.psi.tree.IElementType; 4 | import org.jetbrains.annotations.NonNls; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.nixos.idea.lang.NixLanguage; 7 | 8 | public class NixTokenType extends IElementType { 9 | 10 | public NixTokenType(@NotNull @NonNls String debugName) { 11 | super(debugName, NixLanguage.INSTANCE); 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | if (NixTokenSets.KEYWORDS.contains(this)) { 17 | // The character U+2060 (Word Joiner) is used as a workaround to 18 | // make Grammar-Kit put quotation marks around keywords. See 19 | // https://github.com/JetBrains/Grammar-Kit/issues/262 20 | return "\u2060" + super.toString(); 21 | } 22 | else { 23 | return super.toString(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/psi/impl/NixExprStdPathMixin.kt: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.psi.impl 2 | 3 | import com.intellij.lang.ASTNode 4 | import com.intellij.psi.PsiReference 5 | import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry 6 | 7 | open class NixExprStdPathMixin(node: ASTNode): NixExprPathImpl(node) { 8 | override fun getReferences(): Array = 9 | ReferenceProvidersRegistry.getReferencesFromProviders(this) 10 | } -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/psi/impl/NixParserUtil.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.psi.impl; 2 | 3 | import com.intellij.lang.PsiBuilder; 4 | import com.intellij.lang.parser.GeneratedParserUtilBase; 5 | import com.intellij.openapi.util.Key; 6 | import com.intellij.psi.TokenType; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | public final class NixParserUtil extends GeneratedParserUtilBase { 10 | private static final Key IS_IN_BINDING = Key.create("IS_IN_BINDING"); 11 | 12 | private NixParserUtil() {} // Cannot be instantiated. 13 | 14 | public static boolean parseBindValue(@NotNull PsiBuilder builder, int level, @NotNull Parser expr) { 15 | Boolean oldValue = builder.getUserData(IS_IN_BINDING); 16 | try { 17 | builder.putUserData(IS_IN_BINDING, true); 18 | return expr.parse(builder, level); 19 | } 20 | finally { 21 | builder.putUserData(IS_IN_BINDING, oldValue); 22 | } 23 | } 24 | 25 | public static boolean parseNonBindValue(@NotNull PsiBuilder builder, int level, @NotNull Parser expr) { 26 | Boolean oldValue = builder.getUserData(IS_IN_BINDING); 27 | try { 28 | builder.putUserData(IS_IN_BINDING, null); 29 | return expr.parse(builder, level); 30 | } 31 | finally { 32 | builder.putUserData(IS_IN_BINDING, oldValue); 33 | } 34 | } 35 | 36 | public static boolean parseIsBindValue(@NotNull PsiBuilder builder, int level) { 37 | Boolean isInBinding = builder.getUserData(IS_IN_BINDING); 38 | return isInBinding != null && isInBinding; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/settings/NixExternalFormatterSettings.kt: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.settings 2 | 3 | import com.intellij.openapi.application.ApplicationManager 4 | import com.intellij.openapi.components.BaseState 5 | import com.intellij.openapi.components.RoamingType 6 | import com.intellij.openapi.components.SimplePersistentStateComponent 7 | import com.intellij.openapi.components.State 8 | import com.intellij.openapi.components.Storage 9 | import org.nixos.idea.settings.SimplePersistentStateComponentHelper.delegate 10 | import java.util.ArrayDeque 11 | import java.util.Collections 12 | import java.util.Deque 13 | 14 | @State( 15 | name = "NixExternalFormatterSettings", 16 | storages = [Storage(value = NixStoragePaths.TOOLS, roamingType = RoamingType.LOCAL)] 17 | ) 18 | class NixExternalFormatterSettings : SimplePersistentStateComponent(State()) { 19 | 20 | class State : BaseState() { 21 | var enabled by property(false) 22 | var command by string() 23 | var history: Deque by property(ArrayDeque(), { it.isEmpty() }) 24 | } 25 | 26 | var isFormatEnabled: Boolean by delegate(State::enabled) 27 | var formatCommand: String by delegate(State::command, State::history) 28 | val commandHistory: Collection 29 | get() = Collections.unmodifiableCollection(state.history) 30 | 31 | companion object { 32 | @JvmStatic 33 | fun getInstance(): NixExternalFormatterSettings { 34 | return ApplicationManager.getApplication().getService(NixExternalFormatterSettings::class.java) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/settings/NixStoragePaths.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.settings; 2 | 3 | import com.intellij.openapi.components.RoamingType; 4 | import com.intellij.openapi.components.Storage; 5 | 6 | /** 7 | * Constants to be used for {@link Storage#value()}. 8 | */ 9 | public final class NixStoragePaths { 10 | 11 | /** 12 | * Storage location of non-system dependent settings for this plugin. 13 | * This constant must be used with {@link RoamingType#DEFAULT}. 14 | */ 15 | public static final String DEFAULT = "nix-idea.xml"; 16 | 17 | /** 18 | * Storage location of settings for external tools. 19 | * The settings in the file are considered system dependent. 20 | * This constant must be used with {@link RoamingType#LOCAL}. 21 | */ 22 | public static final String TOOLS = "nix-idea-tools.xml"; 23 | 24 | private NixStoragePaths() {} // Cannot be instantiated 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/settings/NixSymbolSettings.kt: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.settings 2 | 3 | import com.intellij.openapi.application.ApplicationManager 4 | import com.intellij.openapi.components.BaseState 5 | import com.intellij.openapi.components.SimplePersistentStateComponent 6 | import com.intellij.openapi.components.State 7 | import com.intellij.openapi.components.Storage 8 | import org.nixos.idea.settings.SimplePersistentStateComponentHelper.delegate 9 | 10 | @State(name = "NixSymbolSettings", storages = [Storage(NixStoragePaths.DEFAULT)]) 11 | class NixSymbolSettings : SimplePersistentStateComponent(State()) { 12 | 13 | class State : BaseState() { 14 | var enabledPreview by property(false) 15 | var jumpToFirstDeclaration by property(false) 16 | var showDeclarationsAsUsages by property(false) 17 | } 18 | 19 | companion object { 20 | @JvmStatic 21 | fun getInstance(): NixSymbolSettings { 22 | return ApplicationManager.getApplication().getService(NixSymbolSettings::class.java) 23 | } 24 | } 25 | 26 | var enabled: Boolean by delegate(State::enabledPreview) 27 | var jumpToFirstDeclaration by delegate(State::jumpToFirstDeclaration) 28 | var showDeclarationsAsUsages: Boolean by delegate(State::showDeclarationsAsUsages) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/settings/SimplePersistentStateComponentHelper.kt: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.settings 2 | 3 | import com.intellij.openapi.components.BaseState 4 | import com.intellij.openapi.components.SimplePersistentStateComponent 5 | import com.intellij.openapi.util.text.Strings 6 | import java.util.Deque 7 | import kotlin.properties.ReadWriteProperty 8 | import kotlin.reflect.KMutableProperty1 9 | import kotlin.reflect.KProperty 10 | import kotlin.reflect.KProperty1 11 | 12 | internal object SimplePersistentStateComponentHelper { 13 | 14 | private const val MAX_HISTORY_SIZE = 5 15 | 16 | /** 17 | * Creates property which delegates every access to the given property of the state. 18 | * 19 | * ```kotlin 20 | * @State(name = "SomeSettings", storages = [Storage(...)]) 21 | * class SomeSettings : SimplePersistentStateComponent(State()) { 22 | * class State : BaseState() { 23 | * // The internal storage of the configured values 24 | * var enabled by property(true) 25 | * } 26 | * 27 | * // Makes the property publicly accessible 28 | * var enabled: Boolean by delegate(State::enabled) 29 | * } 30 | * ``` 31 | */ 32 | fun delegate(prop: KMutableProperty1) = 33 | object : ReadWriteProperty, V> { 34 | override fun getValue(thisRef: SimplePersistentStateComponent, property: KProperty<*>): V { 35 | return prop.get(thisRef.state) 36 | } 37 | 38 | override fun setValue(thisRef: SimplePersistentStateComponent, property: KProperty<*>, value: V) { 39 | prop.set(thisRef.state, value) 40 | } 41 | } 42 | 43 | /** 44 | * Creates string property with history which delegates every access to the given properties of the state. 45 | * 46 | * ```kotlin 47 | * @State(name = "SomeSettings", storages = [Storage(...)]) 48 | * class SomeSettings : SimplePersistentStateComponent(State()) { 49 | * class State : BaseState() { 50 | * // The internal storage of the configured values 51 | * var command by string() 52 | * var history: Deque by property(ArrayDeque(), { it.isEmpty() }) 53 | * } 54 | * // Makes the property publicly accessible 55 | * var command: String by delegate(State::command, State::history) 56 | * val commandHistory: Collection 57 | * get() = Collections.unmodifiableCollection(state.history) 58 | * } 59 | */ 60 | fun delegate(prop: KMutableProperty1, historyProp: KProperty1>) = 61 | object : ReadWriteProperty, String> { 62 | override fun getValue(thisRef: SimplePersistentStateComponent, property: KProperty<*>): String { 63 | return Strings.notNullize(prop.get(thisRef.state)) 64 | } 65 | 66 | override fun setValue(thisRef: SimplePersistentStateComponent, property: KProperty<*>, value: String) { 67 | val normalized = Strings.nullize(value, true) 68 | prop.set(thisRef.state, normalized) 69 | if (normalized != null) { 70 | val history = historyProp.get(thisRef.state) 71 | history.remove(normalized) 72 | history.addFirst(normalized) 73 | while (history.size > MAX_HISTORY_SIZE) { 74 | history.removeLast() 75 | } 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/settings/ui/NixLangSettingsConfigurable.kt: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.settings.ui 2 | 3 | import com.intellij.openapi.options.BoundSearchableConfigurable 4 | import com.intellij.openapi.options.Configurable 5 | import com.intellij.ui.RawCommandLineEditor 6 | import com.intellij.ui.components.JBCheckBox 7 | import com.intellij.ui.dsl.builder.AlignX 8 | import com.intellij.ui.dsl.builder.Cell 9 | import com.intellij.ui.dsl.builder.MAX_LINE_LENGTH_WORD_WRAP 10 | import com.intellij.ui.dsl.builder.bindSelected 11 | import com.intellij.ui.dsl.builder.panel 12 | import com.intellij.ui.dsl.builder.selected 13 | import org.nixos.idea.settings.NixExternalFormatterSettings 14 | import org.nixos.idea.settings.ui.UiDslExtensions.bindText 15 | import org.nixos.idea.settings.ui.UiDslExtensions.placeholderText 16 | import org.nixos.idea.settings.ui.UiDslExtensions.suggestionsPopup 17 | import org.nixos.idea.settings.ui.UiDslExtensions.validateOnReset 18 | import org.nixos.idea.settings.ui.UiDslExtensions.validateWhenTextChanged 19 | import org.nixos.idea.settings.ui.UiDslExtensions.warnOnInput 20 | 21 | class NixLangSettingsConfigurable : 22 | BoundSearchableConfigurable("Nix", "org.nixos.idea.settings.ui.NixLangSettingsConfigurable"), 23 | Configurable.Beta { 24 | 25 | override fun createPanel() = panel { 26 | group("External Formatter", indent = false) { 27 | val settings = NixExternalFormatterSettings.getInstance() 28 | lateinit var enabledCheckBox: Cell 29 | row { 30 | enabledCheckBox = checkBox("Enable external formatter") 31 | .bindSelected(settings::isFormatEnabled) 32 | .comment( 33 | """ 34 | Format Nix files via an external formatter. 35 | Source of focused file will be passed as standard input. 36 | """.trimIndent(), 37 | MAX_LINE_LENGTH_WORD_WRAP 38 | ) 39 | } 40 | indent { 41 | row("Command:") { 42 | cell(RawCommandLineEditor()) 43 | .bindText(settings::formatCommand) 44 | .placeholderText("Command to execute for formatting") 45 | .suggestionsPopup(settings.commandHistory, BUILTIN_SUGGESTIONS) 46 | .align(AlignX.FILL) 47 | .validateOnReset() 48 | .validateWhenTextChanged() 49 | .warnOnInput("You have to specify the command of the formatter") { 50 | it.text.isNullOrBlank() 51 | } 52 | } 53 | }.enabledIf(enabledCheckBox.selected) 54 | } 55 | } 56 | 57 | override fun apply() { 58 | super.apply() 59 | reset() // Update UI components to use normalized property values 60 | } 61 | } 62 | 63 | private val BUILTIN_SUGGESTIONS: List = listOf( 64 | CommandSuggestionsPopup.Suggestion.builtin( 65 | "Use nixpkgs-fmt from nixpkgs", 66 | "nix --extra-experimental-features \"nix-command flakes\" run nixpkgs#nixpkgs-fmt" 67 | ) 68 | ) 69 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/settings/ui/NixSymbolConfigurable.kt: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.settings.ui 2 | 3 | import com.intellij.openapi.options.BoundSearchableConfigurable 4 | import com.intellij.openapi.options.Configurable 5 | import com.intellij.ui.components.JBCheckBox 6 | import com.intellij.ui.dsl.builder.Cell 7 | import com.intellij.ui.dsl.builder.bind 8 | import com.intellij.ui.dsl.builder.bindSelected 9 | import com.intellij.ui.dsl.builder.panel 10 | import com.intellij.ui.dsl.builder.selected 11 | import org.nixos.idea.settings.NixSymbolSettings 12 | 13 | class NixSymbolConfigurable : 14 | BoundSearchableConfigurable("Symbols", "org.nixos.idea.settings.ui.NixSymbolConfigurable"), 15 | Configurable.Beta { 16 | 17 | override fun createPanel() = panel { 18 | val settings = NixSymbolSettings.getInstance() 19 | lateinit var enabledCheckBox: Cell 20 | row { 21 | enabledCheckBox = checkBox("Use Symbol API to resolve references and find usages") 22 | .bindSelected(settings::enabled) 23 | } 24 | rowsRange { 25 | groupRowsRange("Go To Declaration") { 26 | buttonsGroup { 27 | row { 28 | radioButton("Go to first declaration", true) 29 | radioButton("Ask when symbol has multiple declarations", false) 30 | }.rowComment( 31 | """ 32 | Attribute sets and let-expressions may contain 33 | multiple indirect declarations of the same symbol. 34 | """.trimIndent() 35 | ).contextHelp( 36 | """ 37 | The following code block contains three 38 | declarations of “common”: 39 |
40 |                         let
41 |                           zero = 0;
42 |                           common.a = 1;
43 |                           common.b = 2;
44 |                           common.c = 3;
45 |                         in
46 |                           common
47 |                         
48 | If you run Go To Declaration on the last line, 49 | this setting defines whether 50 | the action jumps directly to common.a 51 | (the first declaration), 52 | or opens a popup asking which declaration you want to see. 53 | """.trimIndent() 54 | ) 55 | }.bind(settings::jumpToFirstDeclaration) 56 | } 57 | groupRowsRange("Find Usages") { 58 | row { 59 | checkBox("Show declarations as part of the results") 60 | .bindSelected(settings::showDeclarationsAsUsages) 61 | } 62 | } 63 | }.enabledIf(enabledCheckBox.selected) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/settings/ui/UiDslExtensions.kt: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.settings.ui 2 | 3 | import com.intellij.openapi.ui.validation.DialogValidationRequestor 4 | import com.intellij.openapi.ui.validation.WHEN_TEXT_CHANGED 5 | import com.intellij.openapi.util.NlsContexts 6 | import com.intellij.openapi.util.NlsContexts.DialogMessage 7 | import com.intellij.ui.RawCommandLineEditor 8 | import com.intellij.ui.TextAccessor 9 | import com.intellij.ui.dsl.builder.Cell 10 | import com.intellij.ui.dsl.builder.MutableProperty 11 | import com.intellij.ui.dsl.builder.toMutableProperty 12 | import org.nixos.idea.settings.ui.CommandSuggestionsPopup.Suggestion 13 | import javax.swing.JComponent 14 | import kotlin.reflect.KMutableProperty0 15 | 16 | object UiDslExtensions { 17 | fun Cell.validateOnReset(): Cell { 18 | return validationRequestor { onReset { it() } } 19 | } 20 | 21 | fun Cell.warnOnInput(@DialogMessage message: String, condition: (T) -> Boolean): Cell { 22 | return validationOnInput { if (condition(it)) warning(message) else null } 23 | } 24 | 25 | fun Cell.bindText(prop: MutableProperty): Cell { 26 | return bind(TextAccessor::getText, TextAccessor::setText, prop) 27 | } 28 | 29 | fun Cell.bindText(prop: KMutableProperty0): Cell { 30 | return bindText(prop.toMutableProperty()) 31 | } 32 | 33 | /** 34 | * Enables validations after changes in the text input. 35 | * Note that this is the default behavior as long as no other [DialogValidationRequestor] is registered. 36 | * This method needs to be called only if you add another requestor, for example via [validateOnReset]. 37 | */ 38 | fun Cell.validateWhenTextChanged(): Cell { 39 | return validationRequestor(DialogValidationRequestor.WithParameter { 40 | WHEN_TEXT_CHANGED(it.textField) 41 | }) 42 | } 43 | 44 | fun Cell.placeholderText(@NlsContexts.StatusText text: String): Cell { 45 | component.editorField.emptyText.setText(text) 46 | component.editorField.accessibleContext.accessibleName = text 47 | return this 48 | } 49 | 50 | fun Cell.suggestionsPopup( 51 | history: Collection, 52 | suggestions: List 53 | ): Cell { 54 | CommandSuggestionsPopup( 55 | component, 56 | history, 57 | suggestions 58 | ).install() 59 | return this 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/util/NixPathVerifier.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.util; 2 | 3 | import java.io.File; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | public class NixPathVerifier { 8 | private String nixpath; 9 | private Map searchPaths; 10 | 11 | public NixPathVerifier(String nixpath) { 12 | this.nixpath = nixpath; 13 | searchPaths = new HashMap(); 14 | this.verify(); 15 | } 16 | 17 | public boolean verify() { 18 | boolean ret = true, fret; 19 | String[] sps = nixpath.split(":"); 20 | for (int i = 0; i < sps.length; i++) { 21 | String[] ns = sps[i].split("="); 22 | String name, path; 23 | File file; 24 | if (ns.length == 2) { 25 | name = ns[0]; 26 | path = ns[1]; 27 | } else { 28 | name = ""; 29 | path = ns[0]; 30 | } 31 | if (path.endsWith(".nix")) 32 | file = new File(path); 33 | else 34 | file = new File(path + File.separator + "default.nix"); 35 | fret = file.exists() && file.canRead(); 36 | if (fret) searchPaths.put(name, file); 37 | ret &= fret; 38 | } 39 | return ret; 40 | } 41 | 42 | public Map asMap() { 43 | return searchPaths; 44 | } 45 | public static Map asMap(String nixpath) { 46 | return (new NixPathVerifier(nixpath)).asMap(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/util/NixVersion.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.util; 2 | 3 | /** 4 | * Known versions of the Nix package manager. 5 | * 6 | * @see Release Notes 7 | */ 8 | public enum NixVersion { 9 | /** 10 | * Release 2.4 (2021-11-01). 11 | */ 12 | V2_04, 13 | /** 14 | * Release 2.5 (2021-12-13). 15 | */ 16 | V2_05, 17 | /** 18 | * Release 2.6 (2022-01-24). 19 | */ 20 | V2_06, 21 | /** 22 | * Release 2.8 (2022-04-19). 23 | */ 24 | V2_08, 25 | /** 26 | * Release 2.9 (2022-05-30). 27 | */ 28 | V2_09, 29 | /** 30 | * Release 2.10 (2022-07-11). 31 | */ 32 | V2_10, 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/nixos/idea/util/TextRangeFactory.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.util; 2 | 3 | import com.intellij.openapi.util.TextRange; 4 | import com.intellij.psi.PsiElement; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.nixos.idea.psi.NixPsiElement; 7 | 8 | /** 9 | * Factory methods to construct {@link TextRange} instances from PSI elements. 10 | */ 11 | public final class TextRangeFactory { 12 | 13 | private TextRangeFactory() {} // Cannot be instantiated 14 | 15 | /** 16 | * Creates {@link TextRange} for an element relative to itself. 17 | * 18 | * @param element The element for which to create the range. 19 | * @return The range with an offset of zero and a length of the given element. 20 | */ 21 | public static @NotNull TextRange root(@NotNull NixPsiElement element) { 22 | return TextRange.from(0, element.getTextLength()); 23 | } 24 | 25 | /** 26 | * Creates {@link TextRange} for an element relative to the given parent. 27 | * 28 | * @param element The element for which to create the range. 29 | * @param parent The parent element which becomes the reference frame for the returned range. 30 | * @return The range of the given {@code element} relative to the given {@code parent}. 31 | */ 32 | public static @NotNull TextRange relative(@NotNull NixPsiElement element, @NotNull NixPsiElement parent) { 33 | assert isChild(element, parent) : element + " not a child of " + parent; 34 | int offset = element.getNode().getStartOffset() - parent.getNode().getStartOffset(); 35 | return TextRange.from(offset, element.getTextLength()); 36 | } 37 | 38 | private static boolean isChild(@NotNull NixPsiElement child, @NotNull NixPsiElement parent) { 39 | for (PsiElement current = child; current != null; current = current.getParent()) { 40 | if (current == parent) { 41 | return true; 42 | } 43 | } 44 | return false; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/nix-idea-ultimate.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 12 | 13 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/pluginIcon_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 3 | -------------------------------------------------------------------------------- /src/main/resources/colorSchemes/NixDarcula.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/colorSchemes/NixDefault.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/icons/nixSnowflake_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 3 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/NixTestExecutionPolicy.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea; 2 | 3 | import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy; 4 | 5 | /** 6 | * Test execution policy referenced by the build setup build.gradle.kts. 7 | * Tests like {@link org.nixos.idea.lang.LexerFilesTest} use it to locate the test data directory. 8 | */ 9 | @SuppressWarnings("unused") 10 | public class NixTestExecutionPolicy extends IdeaTestExecutionPolicy { 11 | @Override 12 | protected String getName() { 13 | return "Nix"; 14 | } 15 | 16 | @Override 17 | public String getHomePath() { 18 | return System.getProperty("plugin.testDataPath"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/_testutil/ExtensionTestUtil.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea._testutil; 2 | 3 | import org.junit.jupiter.api.Tag; 4 | import org.junit.jupiter.api.Test; 5 | import org.junit.jupiter.api.extension.ConditionEvaluationResult; 6 | import org.junit.jupiter.api.extension.ExecutionCondition; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.junit.jupiter.api.extension.ExtensionContext; 9 | import org.junit.platform.engine.DiscoverySelector; 10 | import org.junit.platform.engine.TestExecutionResult; 11 | import org.junit.platform.testkit.engine.EngineExecutionResults; 12 | import org.junit.platform.testkit.engine.EngineTestKit; 13 | import org.junit.platform.testkit.engine.Execution; 14 | import org.junit.platform.testkit.engine.TerminationInfo; 15 | 16 | import java.lang.annotation.*; 17 | import java.util.List; 18 | 19 | final class ExtensionTestUtil { 20 | private static final String TEST_KIT_MARKER = "nix-idea.run-mocks"; 21 | 22 | private ExtensionTestUtil() {} // Cannot be instantiated 23 | 24 | static void runTest(DiscoverySelector selector) throws Throwable { 25 | List executions = runTests(selector).testEvents().executions().list(); 26 | if (executions.size() != 1) { 27 | throw new IllegalStateException("Expected exactly one test execution, got: " + executions); 28 | } 29 | TerminationInfo terminationInfo = executions.get(0).getTerminationInfo(); 30 | TestExecutionResult executionResult = terminationInfo.getExecutionResult(); 31 | if (executionResult.getStatus() != TestExecutionResult.Status.SUCCESSFUL) { 32 | throw executionResult.getThrowable().orElseThrow(); 33 | } 34 | } 35 | 36 | static EngineExecutionResults runTests(DiscoverySelector... selectors) { 37 | return EngineTestKit.engine("junit-jupiter") 38 | .configurationParameter(TEST_KIT_MARKER, "true") 39 | .selectors(selectors) 40 | .execute(); 41 | } 42 | 43 | @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) 44 | @Retention(RetentionPolicy.RUNTIME) 45 | @Documented 46 | @Test 47 | @Tag("mock") 48 | @ExtendWith(DisableOutsideTestKit.class) 49 | @interface MockTest {} 50 | 51 | private static final class DisableOutsideTestKit implements ExecutionCondition { 52 | @Override 53 | public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { 54 | return context.getConfigurationParameter(TEST_KIT_MARKER).isPresent() 55 | ? ConditionEvaluationResult.enabled("Test executed by ExtensionTestUtil") 56 | : ConditionEvaluationResult.disabled("@MockTest triggered outside ExtensionTestUtil"); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/_testutil/MarkersTest.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea._testutil; 2 | 3 | import com.intellij.openapi.util.TextRange; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.List; 7 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; 9 | 10 | final class MarkersTest { 11 | 12 | private static final Markers.TagName TAG_1 = Markers.tagName("tag1"); 13 | private static final Markers.TagName TAG_2 = Markers.tagName("tag2"); 14 | private static final Markers.TagName TAG_3 = Markers.tagName("tag3"); 15 | private static final Markers.TagName TAG_POS = Markers.tagNameVoid("pos"); 16 | 17 | @Test 18 | void testParse() { 19 | Markers markers = Markers.parse( 20 | "abc def ghi ", 21 | TAG_1, TAG_2, TAG_POS); 22 | 23 | assertEquals("abc def ghi ", markers.unmarkedText()); 24 | assertEquals(List.of( 25 | Markers.marker(TAG_1, 4, 11), 26 | Markers.marker(TAG_POS, 9, 9), 27 | Markers.marker(TAG_2, 10, 10), 28 | Markers.marker(TAG_2, 16, 16) 29 | ), markers.list()); 30 | } 31 | 32 | @Test 33 | void testFilter() { 34 | Markers markers = Markers.parse( 35 | "abc def ghi ", 36 | TAG_1, TAG_2, TAG_POS); 37 | 38 | assertEquals(List.of( 39 | Markers.marker(TAG_1, 4, 11) 40 | ), markers.markers(TAG_1).list()); 41 | assertEquals(List.of( 42 | Markers.marker(TAG_2, 10, 10), 43 | Markers.marker(TAG_2, 16, 16) 44 | ), markers.markers(TAG_2).list()); 45 | assertEquals(List.of( 46 | Markers.marker(TAG_POS, 9, 9) 47 | ), markers.markers(TAG_POS).list()); 48 | } 49 | 50 | @Test 51 | void testToString() { 52 | Markers m = Markers.create("123456789", List.of( 53 | Markers.marker(TAG_1, 0, 5), 54 | Markers.marker(TAG_2, 0, 4), 55 | Markers.marker(TAG_3, 0, 6) 56 | ), TAG_1, TAG_2, TAG_3); 57 | 58 | assertEquals("123456789", m.toString()); 59 | } 60 | 61 | @Test 62 | void testEqualsIgnoresOrder() { 63 | Markers m1 = Markers.create("0123456789", TAG_1, List.of( 64 | TextRange.create(0, 5), 65 | TextRange.create(0, 6) 66 | )); 67 | Markers m2 = Markers.create("0123456789", TAG_1, List.of( 68 | TextRange.create(0, 6), 69 | TextRange.create(0, 5) 70 | )); 71 | assertEquals(m1, m2); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/_testutil/ReflectionUtils.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea._testutil; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.junit.jupiter.api.Named; 5 | 6 | import java.lang.reflect.Modifier; 7 | import java.util.Arrays; 8 | import java.util.Objects; 9 | import java.util.stream.Stream; 10 | 11 | public final class ReflectionUtils { 12 | 13 | private ReflectionUtils() { 14 | // Cannot be instantiated. 15 | } 16 | 17 | public static @NotNull Stream> getPublicStaticFieldValues(@NotNull Class owner, @NotNull Class valueType) { 18 | return Arrays.stream(owner.getDeclaredFields()) 19 | .filter(field -> Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) 20 | .map(field -> { 21 | try { 22 | Object value = field.get(null); 23 | if (valueType.isInstance(value)) { 24 | String name = owner.getSimpleName() + "." + field.getName(); 25 | return Named.of(name, valueType.cast(value)); 26 | } 27 | return null; 28 | } catch (IllegalAccessException e) { 29 | throw new IllegalStateException(e); 30 | } 31 | }).filter(Objects::nonNull); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/_testutil/TestFactoryDsl.kt: -------------------------------------------------------------------------------- 1 | package org.nixos.idea._testutil 2 | 3 | import kotlinx.collections.immutable.toImmutableList 4 | import org.junit.jupiter.api.DynamicContainer.dynamicContainer 5 | import org.junit.jupiter.api.DynamicNode 6 | import org.junit.jupiter.api.DynamicTest.dynamicTest 7 | import org.junit.jupiter.api.Named 8 | 9 | @DslMarker 10 | private annotation class TestFactoryDslMarker 11 | 12 | @TestFactoryDslMarker 13 | class TestFactoryDsl private constructor() { 14 | 15 | private val nodes = mutableListOf() 16 | 17 | companion object { 18 | fun testFactory(init: TestFactoryDsl.() -> Unit): List { 19 | val container = TestFactoryDsl() 20 | container.init() 21 | return container.nodes.toImmutableList() 22 | } 23 | } 24 | 25 | fun test(name: String, test: Test.() -> Unit) { 26 | nodes += dynamicTest(name, { test.invoke(Test()) }) 27 | } 28 | 29 | fun container(name: String, init: TestFactoryDsl.() -> Unit) { 30 | val container = TestFactoryDsl() 31 | container.init() 32 | if (container.nodes.isNotEmpty()) { 33 | nodes += dynamicContainer(name, container.nodes.toImmutableList()) 34 | } 35 | } 36 | 37 | fun tests(name: String, data: Iterable, test: Test.(T) -> Unit) { 38 | val list = data.toImmutableList() 39 | when (list.size) { 40 | 0 -> {} 41 | 1 -> nodes += dynamicTest(name, { Test().test(list[0]) }) 42 | else -> nodes += dynamicContainer(name, list.map { dynamicTest(it.toString(), { Test().test(it) }) }) 43 | } 44 | } 45 | 46 | fun containers(name: String, data: Iterable, init: TestFactoryDsl.(T) -> Unit) { 47 | val list = data.flatMap { 48 | val container = TestFactoryDsl() 49 | container.init(it) 50 | if (container.nodes.isEmpty()) { 51 | emptyList() 52 | } else { 53 | listOf(Named.of(it.toString(), container.nodes.toImmutableList())) 54 | } 55 | }.toImmutableList() 56 | when (list.size) { 57 | 0 -> {} 58 | 1 -> nodes += dynamicContainer(name, list[0].payload) 59 | else -> nodes += dynamicContainer(name, list.map { dynamicContainer(it.name, it.payload) }) 60 | } 61 | } 62 | 63 | @TestFactoryDslMarker 64 | class Test 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/lang/LexerFilesTest.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang; 2 | 3 | import com.intellij.lexer.Lexer; 4 | import com.intellij.testFramework.LexerTestCase; 5 | import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.junit.runners.Parameterized; 10 | 11 | import java.io.IOException; 12 | import java.nio.file.Files; 13 | import java.nio.file.Paths; 14 | import java.util.stream.Collectors; 15 | 16 | /** 17 | * Parameterized lexer test for all Nix files inside src/test/testData/ParsingTest/. 18 | */ 19 | @RunWith(Parameterized.class) 20 | public class LexerFilesTest extends LexerTestCase { 21 | private static final String DIRECTORY_NAME = "ParsingTest"; 22 | 23 | private final String filePath; 24 | 25 | public LexerFilesTest(@NotNull String filePath) { 26 | this.filePath = filePath; 27 | } 28 | 29 | /** 30 | * Collects all the files to run this test with. 31 | * 32 | * @return Iterable of files src/test/testData/ParsingTest/*.nix. 33 | */ 34 | @Parameterized.Parameters(name = "{0}") 35 | public static Iterable filePaths() throws IOException { 36 | var baseDir = Paths.get(IdeaTestExecutionPolicy.getHomePathWithPolicy()).resolve(DIRECTORY_NAME); 37 | var fileStream = Files.find(baseDir, 38 | Integer.MAX_VALUE, 39 | (path1, attributes) -> attributes.isRegularFile() && path1.toString().endsWith(".nix")); 40 | 41 | try (fileStream) { 42 | return fileStream.map(path -> baseDir.relativize(path).toString()).collect(Collectors.toList()); 43 | } 44 | } 45 | 46 | @Test 47 | public void check() { 48 | doFileTest("nix"); 49 | } 50 | 51 | @Override 52 | protected Lexer createLexer() { 53 | return new NixLexer(); 54 | } 55 | 56 | @Override 57 | protected String getDirPath() { 58 | return DIRECTORY_NAME; 59 | } 60 | 61 | @Override 62 | protected @NotNull String getTestName(boolean lowercaseFirstLetter) { 63 | return filePath.replace(".nix", ""); 64 | } 65 | 66 | @Override 67 | protected @NotNull String getExpectedFileExtension() { 68 | return ".lexer.txt"; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/lang/LexerTest.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang; 2 | 3 | import com.intellij.lexer.Lexer; 4 | import com.intellij.testFramework.LexerTestCase; 5 | 6 | public final class LexerTest extends LexerTestCase { 7 | public void testRestartabilityWithAntiquotations() { 8 | // Checks that the lexer is restartable. See 9 | // https://intellij-support.jetbrains.com/hc/en-us/community/posts/360010305800 10 | checkCorrectRestart(""" 11 | '' 12 | ${ 13 | [ 14 | "pure string", 15 | "string with ${antiquotation}", 16 | ''ind string with ${multiple} ${antiquotations}'' 17 | ] 18 | } 19 | '' 20 | """); 21 | } 22 | 23 | @Override 24 | protected Lexer createLexer() { 25 | return new NixLexer(); 26 | } 27 | 28 | @Override 29 | protected String getDirPath() { 30 | // We do not use loadTestDataFile(...) 31 | throw new UnsupportedOperationException(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/lang/NixCommenterTest.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang; 2 | 3 | import com.intellij.codeInsight.generation.actions.CommentByBlockCommentAction; 4 | import com.intellij.codeInsight.generation.actions.CommentByLineCommentAction; 5 | import com.intellij.testFramework.fixtures.BasePlatformTestCase; 6 | import org.nixos.idea.file.NixFileType; 7 | 8 | public class NixCommenterTest extends BasePlatformTestCase { 9 | 10 | public void testLineComment() { 11 | myFixture.configureByText(NixFileType.INSTANCE, "services.nginx.enable = true;"); 12 | 13 | CommentByLineCommentAction commentAction = new CommentByLineCommentAction(); 14 | commentAction.actionPerformedImpl(getProject(), myFixture.getEditor()); 15 | myFixture.checkResult("#services.nginx.enable = true;"); 16 | commentAction.actionPerformedImpl(getProject(), myFixture.getEditor()); 17 | myFixture.checkResult("services.nginx.enable = true;"); 18 | } 19 | 20 | public void testBlockComment() { 21 | myFixture.configureByText(NixFileType.INSTANCE, "services.nginx.enable = true;\n"); 22 | 23 | CommentByBlockCommentAction commentAction = new CommentByBlockCommentAction(); 24 | commentAction.actionPerformedImpl(getProject(), myFixture.getEditor()); 25 | myFixture.checkResult("/*services.nginx.enable = true;*/\n"); 26 | commentAction.actionPerformedImpl(getProject(), myFixture.getEditor()); 27 | myFixture.checkResult("services.nginx.enable = true;\n"); 28 | } 29 | } -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/lang/ParsingFailTest.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang; 2 | 3 | import com.intellij.lang.LanguageBraceMatching; 4 | import com.intellij.testFramework.ParsingTestCase; 5 | import com.intellij.testFramework.TestDataPath; 6 | import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy; 7 | 8 | import java.util.Objects; 9 | 10 | @TestDataPath("$PROJECT_ROOT/src/test/testData/ParsingFailTest") 11 | public final class ParsingFailTest extends ParsingTestCase { 12 | public ParsingFailTest() { 13 | super("ParsingFailTest", "nix", new NixParserDefinition()); 14 | } 15 | 16 | // References for the syntax of the Nix Expression Language: 17 | // https://nixos.org/guides/nix-pills/basics-of-language.html 18 | // https://nixos.org/manual/nix/stable/#ch-expression-language 19 | // https://github.com/NixOS/nix/blob/master/src/libexpr/parser.y 20 | 21 | public void testAntiquotationStateSynchronization1() { 22 | // See https://intellij-support.jetbrains.com/hc/en-us/community/posts/360010379000 23 | doTest(true); 24 | } 25 | 26 | public void testAntiquotationStateSynchronization2() { 27 | // See https://intellij-support.jetbrains.com/hc/en-us/community/posts/360010379000 28 | doTest(true); 29 | } 30 | 31 | public void testComment() { 32 | doTest(true); 33 | } 34 | 35 | public void testEmpty() { 36 | doTest(true); 37 | } 38 | 39 | public void testIncompleteExpressionsInBraces() { 40 | doTest(true); 41 | } 42 | 43 | public void testMissingSemicolon() { 44 | doTest(true); 45 | } 46 | 47 | public void testMissingSemicolonTrap() { 48 | doTest(true); 49 | } 50 | 51 | public void testRecoverFromAntiquotation() { 52 | doTest(true); 53 | } 54 | 55 | public void testRecoverFromAssertCondition() { 56 | doTest(true); 57 | } 58 | 59 | public void testRecoverFromIfCondition() { 60 | doTest(true); 61 | } 62 | 63 | public void testRecoverFromIfThenExpression() { 64 | doTest(true); 65 | } 66 | 67 | public void testRecoverFromLetBinding() { 68 | doTest(true); 69 | } 70 | 71 | public void testRecoverFromListItem() { 72 | doTest(true); 73 | } 74 | 75 | public void testRecoverFromParens() { 76 | doTest(true); 77 | } 78 | 79 | public void testRecoverFromParensWithValidSubexpressions() { 80 | doTest(true); 81 | } 82 | 83 | public void testRecoverFromSetBinding() { 84 | doTest(true); 85 | } 86 | 87 | public void testRecoverFromWith() { 88 | doTest(true); 89 | } 90 | 91 | public void testRecWithoutSet() { 92 | doTest(true); 93 | } 94 | 95 | @Override 96 | protected void setUp() throws Exception { 97 | super.setUp(); 98 | // Test environment of ParsingTestCase does not detect the brace matcher on its own. The brace matcher effects the 99 | // error recovery of Grammar-Kit and must therefore be registered to get correct test results. 100 | addExplicitExtension(LanguageBraceMatching.INSTANCE, NixLanguage.INSTANCE, new NixBraceMatcher()); 101 | } 102 | 103 | @Override 104 | protected String getTestDataPath() { 105 | return Objects.requireNonNull(IdeaTestExecutionPolicy.current()).getHomePath(); 106 | } 107 | 108 | @Override 109 | protected boolean includeRanges() { 110 | return true; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/lang/highlighter/NixSyntaxHighlighterTest.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.highlighter; 2 | 3 | import com.intellij.openapi.editor.colors.TextAttributesKey; 4 | import com.intellij.psi.TokenType; 5 | import com.intellij.psi.tree.IElementType; 6 | import com.intellij.psi.tree.TokenSet; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.junit.jupiter.api.Named; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.params.ParameterizedTest; 11 | import org.junit.jupiter.params.provider.MethodSource; 12 | import org.nixos.idea._testutil.ReflectionUtils; 13 | import org.nixos.idea.psi.NixTokenType; 14 | import org.nixos.idea.psi.NixTypes; 15 | 16 | import java.util.stream.IntStream; 17 | import java.util.stream.Stream; 18 | 19 | import static java.util.function.Predicate.not; 20 | import static org.junit.jupiter.api.Assertions.*; 21 | 22 | final class NixSyntaxHighlighterTest { 23 | private static final TokenSet EMPTY_LENGTH_TOKENS = TokenSet.create(NixTypes.PATH_END); 24 | 25 | @Test 26 | void testAttributesKeysForUnknownTokenType() { 27 | TextAttributesKey[] tokenHighlights = new NixSyntaxHighlighter().getTokenHighlights(TokenType.CODE_FRAGMENT); 28 | assertNotNull(tokenHighlights, "tokenHighlights"); 29 | assertEquals(0, tokenHighlights.length, "tokenHighlights.length"); 30 | } 31 | 32 | @ParameterizedTest 33 | @MethodSource 34 | void testAttributesKeysForKnownTokenTypes(@NotNull IElementType tokenType) { 35 | TextAttributesKey[] tokenHighlights = new NixSyntaxHighlighter().getTokenHighlights(tokenType); 36 | assertNotNull(tokenHighlights, "tokenHighlights"); 37 | assertNotEquals(0, tokenHighlights.length, "tokenHighlights.length"); 38 | assertAll(IntStream.range(0, tokenHighlights.length).mapToObj(index -> 39 | () -> assertNotNull(tokenHighlights[index], String.format("tokenHighlights[%d]", index)))); 40 | } 41 | 42 | static @NotNull Stream> testAttributesKeysForKnownTokenTypes() { 43 | return Stream.concat( 44 | Stream.of(Named.of("TokenType.BAD_CHARACTER", TokenType.BAD_CHARACTER)), 45 | ReflectionUtils.getPublicStaticFieldValues(NixTypes.class, NixTokenType.class) 46 | ).filter(not(named -> EMPTY_LENGTH_TOKENS.contains(named.getPayload()))); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/lang/highlighter/NixTextAttributesTest.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.lang.highlighter; 2 | 3 | import com.intellij.openapi.editor.colors.TextAttributesKey; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.junit.jupiter.api.Named; 6 | import org.junit.jupiter.params.ParameterizedTest; 7 | import org.junit.jupiter.params.provider.MethodSource; 8 | import org.nixos.idea._testutil.ReflectionUtils; 9 | 10 | import java.util.Set; 11 | import java.util.stream.Collectors; 12 | import java.util.stream.Stream; 13 | 14 | import static org.junit.jupiter.api.Assertions.assertTrue; 15 | import static org.junit.jupiter.api.Assertions.fail; 16 | 17 | final class NixTextAttributesTest { 18 | @ParameterizedTest 19 | @MethodSource 20 | void testKeyNamesHaveNixPrefix(@NotNull TextAttributesKey key) { 21 | assertTrue(key.getExternalName().startsWith("NIX_")); 22 | } 23 | 24 | static @NotNull Stream> testKeyNamesHaveNixPrefix() { 25 | return ReflectionUtils.getPublicStaticFieldValues(NixTextAttributes.class, TextAttributesKey.class); 26 | } 27 | 28 | @ParameterizedTest 29 | @MethodSource 30 | void testNoDuplicateKeyNames(@NotNull TextAttributesKey key) { 31 | Set duplicates = ReflectionUtils.getPublicStaticFieldValues(NixTextAttributes.class, TextAttributesKey.class) 32 | .filter(other -> other.getPayload().getExternalName().equals(key.getExternalName())) 33 | .map(Named::getName) 34 | .collect(Collectors.toSet()); 35 | if (duplicates.size() != 1) { 36 | fail("Duplicates: " + duplicates); 37 | } 38 | } 39 | 40 | static @NotNull Stream> testNoDuplicateKeyNames() { 41 | return ReflectionUtils.getPublicStaticFieldValues(NixTextAttributes.class, TextAttributesKey.class); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/psi/NixPsiUtilTest.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.psi; 2 | 3 | import com.intellij.openapi.project.Project; 4 | import com.intellij.openapi.util.TextRange; 5 | import org.junit.jupiter.params.ParameterizedTest; 6 | import org.junit.jupiter.params.provider.CsvSource; 7 | import org.nixos.idea._testutil.Markers; 8 | import org.nixos.idea._testutil.WithIdeaPlatform; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | 12 | @WithIdeaPlatform.OnEdt 13 | final class NixPsiUtilTest { 14 | 15 | private final Project myProject; 16 | 17 | NixPsiUtilTest(Project project) { 18 | myProject = project; 19 | } 20 | 21 | @ParameterizedTest(name = "[{index}] {0} => {1}") 22 | @CsvSource(delimiterString = "=>", textBlock = """ 23 | x => false 24 | x.y => false 25 | x.y => false 26 | { inherit x } => false 27 | { x = _ } => true 28 | { x.y = _ } => true 29 | { x.y = _ } => true 30 | let { x = _ } => true 31 | rec { x = _ } => true 32 | x: _ => true 33 | { x, y }: _ => true 34 | x @ { y }: _ => true 35 | x @ { y }: _ => true 36 | """) 37 | void isDeclaration(String code, boolean expectedResult) { 38 | Markers markedCode = Markers.parse(code, Markers.tagName("attr")); 39 | TextRange attr = markedCode.single().range(); 40 | NixIdentifier element = NixElementFactory.createElement( 41 | myProject, 42 | NixIdentifier.class, 43 | markedCode.unmarkedText().substring(0, attr.getStartOffset()), 44 | attr.substring(markedCode.unmarkedText()), 45 | markedCode.unmarkedText().substring(attr.getEndOffset())); 46 | assertEquals(expectedResult, NixPsiUtil.isDeclaration(element)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/org/nixos/idea/settings/ui/NixColorSettingsPageTest.java: -------------------------------------------------------------------------------- 1 | package org.nixos.idea.settings.ui; 2 | 3 | import com.intellij.openapi.editor.colors.TextAttributesKey; 4 | import com.intellij.openapi.options.colors.AttributesDescriptor; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.junit.jupiter.api.Named; 7 | import org.junit.jupiter.params.ParameterizedTest; 8 | import org.junit.jupiter.params.provider.MethodSource; 9 | import org.nixos.idea._testutil.ReflectionUtils; 10 | import org.nixos.idea.lang.highlighter.NixTextAttributes; 11 | 12 | import java.util.Arrays; 13 | import java.util.stream.Stream; 14 | 15 | import static org.junit.jupiter.api.Assertions.assertTrue; 16 | 17 | final class NixColorSettingsPageTest { 18 | @ParameterizedTest 19 | @MethodSource 20 | void testNoKeyMissing(@NotNull TextAttributesKey textAttributesKey) { 21 | AttributesDescriptor[] descriptors = new NixColorSettingsPage().getAttributeDescriptors(); 22 | assertTrue(Arrays.stream(descriptors) 23 | .map(AttributesDescriptor::getKey) 24 | .anyMatch(textAttributesKey::equals)); 25 | } 26 | 27 | static @NotNull Stream> testNoKeyMissing() { 28 | return ReflectionUtils.getPublicStaticFieldValues(NixTextAttributes.class, TextAttributesKey.class); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/AntiquotationStateSynchronization1.nix: -------------------------------------------------------------------------------- 1 | "${ {{${{ }}}} "" }" end 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/AntiquotationStateSynchronization1.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,24) 2 | NixExprAppImpl(EXPR_APP)(0,24) 3 | NixStdStringImpl(STD_STRING)(0,20) 4 | PsiElement(STRING_OPEN)('"')(0,1) 5 | NixAntiquotationImpl(ANTIQUOTATION)(1,19) 6 | PsiElement($)('$')(1,2) 7 | PsiElement({)('{')(2,3) 8 | PsiWhiteSpace(' ')(3,4) 9 | NixExprAppImpl(EXPR_APP)(4,17) 10 | NixExprAttrsImpl(EXPR_ATTRS)(4,14) 11 | PsiElement({)('{')(4,5) 12 | PsiElement(DUMMY_BLOCK)(5,13) 13 | PsiErrorElement:'{' unexpected(5,6) 14 | PsiElement({)('{')(5,6) 15 | PsiElement(DUMMY_BLOCK)(6,7) 16 | PsiElement($)('$')(6,7) 17 | PsiElement(DUMMY_BLOCK)(7,12) 18 | PsiElement({)('{')(7,8) 19 | PsiElement(DUMMY_BLOCK)(8,11) 20 | PsiElement({)('{')(8,9) 21 | PsiWhiteSpace(' ')(9,10) 22 | PsiElement(})('}')(10,11) 23 | PsiElement(})('}')(11,12) 24 | PsiElement(})('}')(12,13) 25 | PsiElement(})('}')(13,14) 26 | PsiWhiteSpace(' ')(14,15) 27 | NixStdStringImpl(STD_STRING)(15,17) 28 | PsiElement(STRING_OPEN)('"')(15,16) 29 | PsiElement(STRING_CLOSE)('"')(16,17) 30 | PsiWhiteSpace(' ')(17,18) 31 | PsiElement(})('}')(18,19) 32 | PsiElement(STRING_CLOSE)('"')(19,20) 33 | PsiWhiteSpace(' ')(20,21) 34 | NixExprVarImpl(EXPR_VAR)(21,24) 35 | PsiElement(ID)('end')(21,24) 36 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/AntiquotationStateSynchronization2.nix: -------------------------------------------------------------------------------- 1 | "${ ([ } ])" end 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/AntiquotationStateSynchronization2.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,16) 2 | NixExprAppImpl(EXPR_APP)(0,16) 3 | NixStdStringImpl(STD_STRING)(0,12) 4 | PsiElement(STRING_OPEN)('"')(0,1) 5 | NixAntiquotationImpl(ANTIQUOTATION)(1,8) 6 | PsiElement($)('$')(1,2) 7 | PsiElement({)('{')(2,3) 8 | PsiWhiteSpace(' ')(3,4) 9 | NixExprParensImpl(EXPR_PARENS)(4,6) 10 | PsiElement(()('(')(4,5) 11 | NixExprListImpl(EXPR_LIST)(5,6) 12 | PsiElement([)('[')(5,6) 13 | PsiErrorElement: or ']' expected, got '}'(6,6) 14 | 15 | PsiWhiteSpace(' ')(6,7) 16 | PsiElement(})('}')(7,8) 17 | NixStringTextImpl(STRING_TEXT)(8,11) 18 | PsiElement(STR)(' ])')(8,11) 19 | PsiElement(STRING_CLOSE)('"')(11,12) 20 | PsiWhiteSpace(' ')(12,13) 21 | NixExprVarImpl(EXPR_VAR)(13,16) 22 | PsiElement(ID)('end')(13,16) 23 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/Comment.nix: -------------------------------------------------------------------------------- 1 | # single-line 2 | /* inline/multi-line */ 3 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/Comment.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,37) 2 | PsiErrorElement: expected(0,0) 3 | 4 | PsiComment(SCOMMENT)('# single-line')(0,13) 5 | PsiWhiteSpace('\n')(13,14) 6 | PsiComment(MCOMMENT)('/* inline/multi-line */')(14,37) 7 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/Empty.nix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NixOS/nix-idea/511fa35445ba35078beb83496d9c0795a6664ba3/src/test/testData/ParsingFailTest/Empty.nix -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/Empty.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,0) 2 | PsiErrorElement: expected(0,0) 3 | 4 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/IncompleteExpressionsInBraces.nix: -------------------------------------------------------------------------------- 1 | # Braces should always win during error recovery of other expressions 2 | (assert) 3 | (if) 4 | (if a then) 5 | (let b = c;) 6 | (with d) 7 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/IncompleteExpressionsInBraces.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,117) 2 | PsiComment(SCOMMENT)('# Braces should always win during error recovery of other expressions')(0,69) 3 | PsiWhiteSpace('\n')(69,70) 4 | NixExprAppImpl(EXPR_APP)(70,117) 5 | NixExprParensImpl(EXPR_PARENS)(70,78) 6 | PsiElement(()('(')(70,71) 7 | NixExprAssertImpl(EXPR_ASSERT)(71,77) 8 | PsiElement(⁠assert)('assert')(71,77) 9 | PsiErrorElement: expected, got ')'(77,77) 10 | 11 | PsiElement())(')')(77,78) 12 | PsiWhiteSpace('\n')(78,79) 13 | NixExprParensImpl(EXPR_PARENS)(79,83) 14 | PsiElement(()('(')(79,80) 15 | NixExprIfImpl(EXPR_IF)(80,82) 16 | PsiElement(⁠if)('if')(80,82) 17 | PsiErrorElement: expected, got ')'(82,82) 18 | 19 | PsiElement())(')')(82,83) 20 | PsiWhiteSpace('\n')(83,84) 21 | NixExprParensImpl(EXPR_PARENS)(84,95) 22 | PsiElement(()('(')(84,85) 23 | NixExprIfImpl(EXPR_IF)(85,94) 24 | PsiElement(⁠if)('if')(85,87) 25 | PsiWhiteSpace(' ')(87,88) 26 | NixExprVarImpl(EXPR_VAR)(88,89) 27 | PsiElement(ID)('a')(88,89) 28 | PsiWhiteSpace(' ')(89,90) 29 | PsiElement(⁠then)('then')(90,94) 30 | PsiErrorElement: expected, got ')'(94,94) 31 | 32 | PsiElement())(')')(94,95) 33 | PsiWhiteSpace('\n')(95,96) 34 | NixExprParensImpl(EXPR_PARENS)(96,108) 35 | PsiElement(()('(')(96,97) 36 | NixExprLetImpl(EXPR_LET)(97,107) 37 | PsiElement(⁠let)('let')(97,100) 38 | PsiWhiteSpace(' ')(100,101) 39 | NixBindAttrImpl(BIND_ATTR)(101,107) 40 | NixAttrPathImpl(ATTR_PATH)(101,102) 41 | NixStdAttrImpl(STD_ATTR)(101,102) 42 | PsiElement(ID)('b')(101,102) 43 | PsiWhiteSpace(' ')(102,103) 44 | PsiElement(=)('=')(103,104) 45 | PsiWhiteSpace(' ')(104,105) 46 | NixExprVarImpl(EXPR_VAR)(105,106) 47 | PsiElement(ID)('c')(105,106) 48 | PsiElement(;)(';')(106,107) 49 | PsiErrorElement: or '⁠in' expected, got ')'(107,107) 50 | 51 | PsiElement())(')')(107,108) 52 | PsiWhiteSpace('\n')(108,109) 53 | NixExprParensImpl(EXPR_PARENS)(109,117) 54 | PsiElement(()('(')(109,110) 55 | NixExprWithImpl(EXPR_WITH)(110,116) 56 | PsiElement(⁠with)('with')(110,114) 57 | PsiWhiteSpace(' ')(114,115) 58 | NixExprVarImpl(EXPR_VAR)(115,116) 59 | PsiElement(ID)('d')(115,116) 60 | PsiErrorElement:'.', ':', ';', , '@' or '⁠or' expected, got ')'(116,116) 61 | 62 | PsiElement())(')')(116,117) 63 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/MissingSemicolon.nix: -------------------------------------------------------------------------------- 1 | { 2 | k1 = v1 3 | k2 = v2 4 | } 5 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/MissingSemicolon.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,19) 2 | NixExprAttrsImpl(EXPR_ATTRS)(0,19) 3 | PsiElement({)('{')(0,1) 4 | PsiWhiteSpace('\n')(1,2) 5 | NixBindAttrImpl(BIND_ATTR)(2,9) 6 | NixAttrPathImpl(ATTR_PATH)(2,4) 7 | NixStdAttrImpl(STD_ATTR)(2,4) 8 | PsiElement(ID)('k1')(2,4) 9 | PsiWhiteSpace(' ')(4,5) 10 | PsiElement(=)('=')(5,6) 11 | PsiWhiteSpace(' ')(6,7) 12 | NixExprVarImpl(EXPR_VAR)(7,9) 13 | PsiElement(ID)('v1')(7,9) 14 | PsiErrorElement:';' expected, got 'k2'(9,9) 15 | 16 | PsiWhiteSpace('\n')(9,10) 17 | NixBindAttrImpl(BIND_ATTR)(10,17) 18 | NixAttrPathImpl(ATTR_PATH)(10,12) 19 | NixStdAttrImpl(STD_ATTR)(10,12) 20 | PsiElement(ID)('k2')(10,12) 21 | PsiWhiteSpace(' ')(12,13) 22 | PsiElement(=)('=')(13,14) 23 | PsiWhiteSpace(' ')(14,15) 24 | NixExprVarImpl(EXPR_VAR)(15,17) 25 | PsiElement(ID)('v2')(15,17) 26 | PsiErrorElement:';' expected, got '}'(17,17) 27 | 28 | PsiWhiteSpace('\n')(17,18) 29 | PsiElement(})('}')(18,19) 30 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/MissingSemicolonTrap.nix: -------------------------------------------------------------------------------- 1 | # Ensures that the detection for missing semicolons does not trigger 2 | # when no semicolon is expected. 3 | { 4 | k = (a b = c); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/MissingSemicolonTrap.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,120) 2 | PsiComment(SCOMMENT)('# Ensures that the detection for missing semicolons does not trigger')(0,68) 3 | PsiWhiteSpace('\n')(68,69) 4 | PsiComment(SCOMMENT)('# when no semicolon is expected.')(69,101) 5 | PsiWhiteSpace('\n')(101,102) 6 | NixExprAttrsImpl(EXPR_ATTRS)(102,120) 7 | PsiElement({)('{')(102,103) 8 | PsiWhiteSpace('\n')(103,104) 9 | NixBindAttrImpl(BIND_ATTR)(104,118) 10 | NixAttrPathImpl(ATTR_PATH)(104,105) 11 | NixStdAttrImpl(STD_ATTR)(104,105) 12 | PsiElement(ID)('k')(104,105) 13 | PsiWhiteSpace(' ')(105,106) 14 | PsiElement(=)('=')(106,107) 15 | PsiWhiteSpace(' ')(107,108) 16 | NixExprParensImpl(EXPR_PARENS)(108,117) 17 | PsiElement(()('(')(108,109) 18 | NixExprAppImpl(EXPR_APP)(109,112) 19 | NixExprVarImpl(EXPR_VAR)(109,110) 20 | PsiElement(ID)('a')(109,110) 21 | PsiWhiteSpace(' ')(110,111) 22 | NixExprVarImpl(EXPR_VAR)(111,112) 23 | PsiElement(ID)('b')(111,112) 24 | PsiWhiteSpace(' ')(112,113) 25 | PsiErrorElement:'.', or '⁠or' expected, got '='(113,114) 26 | PsiElement(=)('=')(113,114) 27 | PsiWhiteSpace(' ')(114,115) 28 | PsiElement(ID)('c')(115,116) 29 | PsiElement())(')')(116,117) 30 | PsiElement(;)(';')(117,118) 31 | PsiWhiteSpace('\n')(118,119) 32 | PsiElement(})('}')(119,120) 33 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecWithoutSet.nix: -------------------------------------------------------------------------------- 1 | rec \\ 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecWithoutSet.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,6) 2 | PsiElement(⁠rec)('rec')(0,3) 3 | PsiWhiteSpace(' ')(3,4) 4 | PsiErrorElement:'{' expected, got '\'(4,5) 5 | PsiElement(BAD_CHARACTER)('\')(4,5) 6 | PsiElement(BAD_CHARACTER)('\')(5,6) 7 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromAntiquotation.nix: -------------------------------------------------------------------------------- 1 | "${ \\ }" 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromAntiquotation.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,9) 2 | NixStdStringImpl(STD_STRING)(0,9) 3 | PsiElement(STRING_OPEN)('"')(0,1) 4 | NixAntiquotationImpl(ANTIQUOTATION)(1,8) 5 | PsiElement($)('$')(1,2) 6 | PsiElement({)('{')(2,3) 7 | PsiErrorElement: expected, got '\'(3,3) 8 | 9 | PsiWhiteSpace(' ')(3,4) 10 | PsiErrorElement: expected, got '\'(4,5) 11 | PsiElement(BAD_CHARACTER)('\')(4,5) 12 | PsiElement(BAD_CHARACTER)('\')(5,6) 13 | PsiWhiteSpace(' ')(6,7) 14 | PsiElement(})('}')(7,8) 15 | PsiElement(STRING_CLOSE)('"')(8,9) 16 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromAssertCondition.nix: -------------------------------------------------------------------------------- 1 | assert \\ a; b 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromAssertCondition.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,14) 2 | NixExprAssertImpl(EXPR_ASSERT)(0,6) 3 | PsiElement(⁠assert)('assert')(0,6) 4 | PsiErrorElement: expected, got '\'(6,6) 5 | 6 | PsiWhiteSpace(' ')(6,7) 7 | PsiElement(BAD_CHARACTER)('\')(7,8) 8 | PsiElement(BAD_CHARACTER)('\')(8,9) 9 | PsiWhiteSpace(' ')(9,10) 10 | PsiElement(ID)('a')(10,11) 11 | PsiElement(;)(';')(11,12) 12 | PsiWhiteSpace(' ')(12,13) 13 | PsiElement(ID)('b')(13,14) 14 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromIfCondition.nix: -------------------------------------------------------------------------------- 1 | if \\ a then b else c 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromIfCondition.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,21) 2 | NixExprIfImpl(EXPR_IF)(0,2) 3 | PsiElement(⁠if)('if')(0,2) 4 | PsiErrorElement: expected, got '\'(2,2) 5 | 6 | PsiWhiteSpace(' ')(2,3) 7 | PsiElement(BAD_CHARACTER)('\')(3,4) 8 | PsiElement(BAD_CHARACTER)('\')(4,5) 9 | PsiWhiteSpace(' ')(5,6) 10 | PsiElement(ID)('a')(6,7) 11 | PsiWhiteSpace(' ')(7,8) 12 | PsiElement(⁠then)('then')(8,12) 13 | PsiWhiteSpace(' ')(12,13) 14 | PsiElement(ID)('b')(13,14) 15 | PsiWhiteSpace(' ')(14,15) 16 | PsiElement(⁠else)('else')(15,19) 17 | PsiWhiteSpace(' ')(19,20) 18 | PsiElement(ID)('c')(20,21) 19 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromIfThenExpression.nix: -------------------------------------------------------------------------------- 1 | if a then \\ b else c 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromIfThenExpression.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,21) 2 | NixExprIfImpl(EXPR_IF)(0,9) 3 | PsiElement(⁠if)('if')(0,2) 4 | PsiWhiteSpace(' ')(2,3) 5 | NixExprVarImpl(EXPR_VAR)(3,4) 6 | PsiElement(ID)('a')(3,4) 7 | PsiWhiteSpace(' ')(4,5) 8 | PsiElement(⁠then)('then')(5,9) 9 | PsiErrorElement: expected, got '\'(9,9) 10 | 11 | PsiWhiteSpace(' ')(9,10) 12 | PsiElement(BAD_CHARACTER)('\')(10,11) 13 | PsiElement(BAD_CHARACTER)('\')(11,12) 14 | PsiWhiteSpace(' ')(12,13) 15 | PsiElement(ID)('b')(13,14) 16 | PsiWhiteSpace(' ')(14,15) 17 | PsiElement(⁠else)('else')(15,19) 18 | PsiWhiteSpace(' ')(19,20) 19 | PsiElement(ID)('c')(20,21) 20 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromLetBinding.nix: -------------------------------------------------------------------------------- 1 | let \\ a = b; \\ c = d; \\ in e 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromLetBinding.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,31) 2 | NixExprLetImpl(EXPR_LET)(0,31) 3 | PsiElement(⁠let)('let')(0,3) 4 | PsiWhiteSpace(' ')(3,4) 5 | PsiErrorElement:'\' unexpected(4,5) 6 | PsiElement(BAD_CHARACTER)('\')(4,5) 7 | PsiElement(BAD_CHARACTER)('\')(5,6) 8 | PsiWhiteSpace(' ')(6,7) 9 | NixBindAttrImpl(BIND_ATTR)(7,13) 10 | NixAttrPathImpl(ATTR_PATH)(7,8) 11 | NixStdAttrImpl(STD_ATTR)(7,8) 12 | PsiElement(ID)('a')(7,8) 13 | PsiWhiteSpace(' ')(8,9) 14 | PsiElement(=)('=')(9,10) 15 | PsiWhiteSpace(' ')(10,11) 16 | NixExprVarImpl(EXPR_VAR)(11,12) 17 | PsiElement(ID)('b')(11,12) 18 | PsiElement(;)(';')(12,13) 19 | PsiWhiteSpace(' ')(13,14) 20 | PsiErrorElement:'\' unexpected(14,15) 21 | PsiElement(BAD_CHARACTER)('\')(14,15) 22 | PsiElement(BAD_CHARACTER)('\')(15,16) 23 | PsiWhiteSpace(' ')(16,17) 24 | NixBindAttrImpl(BIND_ATTR)(17,23) 25 | NixAttrPathImpl(ATTR_PATH)(17,18) 26 | NixStdAttrImpl(STD_ATTR)(17,18) 27 | PsiElement(ID)('c')(17,18) 28 | PsiWhiteSpace(' ')(18,19) 29 | PsiElement(=)('=')(19,20) 30 | PsiWhiteSpace(' ')(20,21) 31 | NixExprVarImpl(EXPR_VAR)(21,22) 32 | PsiElement(ID)('d')(21,22) 33 | PsiElement(;)(';')(22,23) 34 | PsiWhiteSpace(' ')(23,24) 35 | PsiErrorElement:'\' unexpected(24,25) 36 | PsiElement(BAD_CHARACTER)('\')(24,25) 37 | PsiElement(BAD_CHARACTER)('\')(25,26) 38 | PsiWhiteSpace(' ')(26,27) 39 | PsiElement(⁠in)('in')(27,29) 40 | PsiWhiteSpace(' ')(29,30) 41 | NixExprVarImpl(EXPR_VAR)(30,31) 42 | PsiElement(ID)('e')(30,31) 43 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromListItem.nix: -------------------------------------------------------------------------------- 1 | [ \\ a \\ b \\ ] c 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromListItem.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,18) 2 | NixExprAppImpl(EXPR_APP)(0,18) 3 | NixExprListImpl(EXPR_LIST)(0,16) 4 | PsiElement([)('[')(0,1) 5 | PsiWhiteSpace(' ')(1,2) 6 | PsiErrorElement:'\' unexpected(2,3) 7 | PsiElement(BAD_CHARACTER)('\')(2,3) 8 | PsiElement(BAD_CHARACTER)('\')(3,4) 9 | PsiWhiteSpace(' ')(4,5) 10 | NixExprVarImpl(EXPR_VAR)(5,6) 11 | PsiElement(ID)('a')(5,6) 12 | PsiWhiteSpace(' ')(6,7) 13 | PsiErrorElement:'.' or '⁠or' expected, got '\'(7,8) 14 | PsiElement(BAD_CHARACTER)('\')(7,8) 15 | PsiElement(BAD_CHARACTER)('\')(8,9) 16 | PsiWhiteSpace(' ')(9,10) 17 | NixExprVarImpl(EXPR_VAR)(10,11) 18 | PsiElement(ID)('b')(10,11) 19 | PsiWhiteSpace(' ')(11,12) 20 | PsiErrorElement:'.' or '⁠or' expected, got '\'(12,13) 21 | PsiElement(BAD_CHARACTER)('\')(12,13) 22 | PsiElement(BAD_CHARACTER)('\')(13,14) 23 | PsiWhiteSpace(' ')(14,15) 24 | PsiElement(])(']')(15,16) 25 | PsiWhiteSpace(' ')(16,17) 26 | NixExprVarImpl(EXPR_VAR)(17,18) 27 | PsiElement(ID)('c')(17,18) 28 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromParens.nix: -------------------------------------------------------------------------------- 1 | ( \\ ) end 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromParens.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,10) 2 | NixExprAppImpl(EXPR_APP)(0,10) 3 | NixExprParensImpl(EXPR_PARENS)(0,6) 4 | PsiElement(()('(')(0,1) 5 | PsiErrorElement: expected, got '\'(1,1) 6 | 7 | PsiWhiteSpace(' ')(1,2) 8 | PsiErrorElement: expected, got '\'(2,3) 9 | PsiElement(BAD_CHARACTER)('\')(2,3) 10 | PsiElement(BAD_CHARACTER)('\')(3,4) 11 | PsiWhiteSpace(' ')(4,5) 12 | PsiElement())(')')(5,6) 13 | PsiWhiteSpace(' ')(6,7) 14 | NixExprVarImpl(EXPR_VAR)(7,10) 15 | PsiElement(ID)('end')(7,10) 16 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromParensWithValidSubexpressions.nix: -------------------------------------------------------------------------------- 1 | ( a \\ b ) end 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromParensWithValidSubexpressions.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,14) 2 | NixExprAppImpl(EXPR_APP)(0,14) 3 | NixExprParensImpl(EXPR_PARENS)(0,10) 4 | PsiElement(()('(')(0,1) 5 | PsiWhiteSpace(' ')(1,2) 6 | NixExprVarImpl(EXPR_VAR)(2,3) 7 | PsiElement(ID)('a')(2,3) 8 | PsiWhiteSpace(' ')(3,4) 9 | PsiErrorElement:'.', ':', , '@' or '⁠or' expected, got '\'(4,5) 10 | PsiElement(BAD_CHARACTER)('\')(4,5) 11 | PsiElement(BAD_CHARACTER)('\')(5,6) 12 | PsiWhiteSpace(' ')(6,7) 13 | PsiElement(ID)('b')(7,8) 14 | PsiWhiteSpace(' ')(8,9) 15 | PsiElement())(')')(9,10) 16 | PsiWhiteSpace(' ')(10,11) 17 | NixExprVarImpl(EXPR_VAR)(11,14) 18 | PsiElement(ID)('end')(11,14) 19 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromSetBinding.nix: -------------------------------------------------------------------------------- 1 | { \\ a = b; \\ c = d; \\ } e 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromSetBinding.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,28) 2 | NixExprAppImpl(EXPR_APP)(0,28) 3 | NixExprAttrsImpl(EXPR_ATTRS)(0,26) 4 | PsiElement({)('{')(0,1) 5 | PsiWhiteSpace(' ')(1,2) 6 | PsiErrorElement:'\' unexpected(2,3) 7 | PsiElement(BAD_CHARACTER)('\')(2,3) 8 | PsiElement(BAD_CHARACTER)('\')(3,4) 9 | PsiWhiteSpace(' ')(4,5) 10 | NixBindAttrImpl(BIND_ATTR)(5,11) 11 | NixAttrPathImpl(ATTR_PATH)(5,6) 12 | NixStdAttrImpl(STD_ATTR)(5,6) 13 | PsiElement(ID)('a')(5,6) 14 | PsiWhiteSpace(' ')(6,7) 15 | PsiElement(=)('=')(7,8) 16 | PsiWhiteSpace(' ')(8,9) 17 | NixExprVarImpl(EXPR_VAR)(9,10) 18 | PsiElement(ID)('b')(9,10) 19 | PsiElement(;)(';')(10,11) 20 | PsiWhiteSpace(' ')(11,12) 21 | PsiErrorElement:'\' unexpected(12,13) 22 | PsiElement(BAD_CHARACTER)('\')(12,13) 23 | PsiElement(BAD_CHARACTER)('\')(13,14) 24 | PsiWhiteSpace(' ')(14,15) 25 | NixBindAttrImpl(BIND_ATTR)(15,21) 26 | NixAttrPathImpl(ATTR_PATH)(15,16) 27 | NixStdAttrImpl(STD_ATTR)(15,16) 28 | PsiElement(ID)('c')(15,16) 29 | PsiWhiteSpace(' ')(16,17) 30 | PsiElement(=)('=')(17,18) 31 | PsiWhiteSpace(' ')(18,19) 32 | NixExprVarImpl(EXPR_VAR)(19,20) 33 | PsiElement(ID)('d')(19,20) 34 | PsiElement(;)(';')(20,21) 35 | PsiWhiteSpace(' ')(21,22) 36 | PsiErrorElement:'\' unexpected(22,23) 37 | PsiElement(BAD_CHARACTER)('\')(22,23) 38 | PsiElement(BAD_CHARACTER)('\')(23,24) 39 | PsiWhiteSpace(' ')(24,25) 40 | PsiElement(})('}')(25,26) 41 | PsiWhiteSpace(' ')(26,27) 42 | NixExprVarImpl(EXPR_VAR)(27,28) 43 | PsiElement(ID)('e')(27,28) 44 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromWith.nix: -------------------------------------------------------------------------------- 1 | with \\ a; b 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingFailTest/RecoverFromWith.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,12) 2 | NixExprWithImpl(EXPR_WITH)(0,4) 3 | PsiElement(⁠with)('with')(0,4) 4 | PsiErrorElement: expected, got '\'(4,4) 5 | 6 | PsiWhiteSpace(' ')(4,5) 7 | PsiElement(BAD_CHARACTER)('\')(5,6) 8 | PsiElement(BAD_CHARACTER)('\')(6,7) 9 | PsiWhiteSpace(' ')(7,8) 10 | PsiElement(ID)('a')(8,9) 11 | PsiElement(;)(';')(9,10) 12 | PsiWhiteSpace(' ')(10,11) 13 | PsiElement(ID)('b')(11,12) 14 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Assertion.lexer.txt: -------------------------------------------------------------------------------- 1 | ⁠assert ('assert') 2 | WHITE_SPACE (' ') 3 | ID ('e1') 4 | ; (';') 5 | WHITE_SPACE (' ') 6 | ID ('e2') 7 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Assertion.nix: -------------------------------------------------------------------------------- 1 | assert e1; e2 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Assertion.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,13) 2 | NixExprAssertImpl(EXPR_ASSERT)(0,13) 3 | PsiElement(⁠assert)('assert')(0,6) 4 | PsiWhiteSpace(' ')(6,7) 5 | NixExprVarImpl(EXPR_VAR)(7,9) 6 | PsiElement(ID)('e1')(7,9) 7 | PsiElement(;)(';')(9,10) 8 | PsiWhiteSpace(' ')(10,11) 9 | NixExprVarImpl(EXPR_VAR)(11,13) 10 | PsiElement(ID)('e2')(11,13) 11 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Boolean.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | ID ('true') 4 | WHITE_SPACE ('\n') 5 | ID ('false') 6 | WHITE_SPACE ('\n') 7 | ] (']') 8 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Boolean.nix: -------------------------------------------------------------------------------- 1 | [ 2 | true 3 | false 4 | ] 5 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Boolean.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,14) 2 | NixExprListImpl(EXPR_LIST)(0,14) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace('\n')(1,2) 5 | NixExprVarImpl(EXPR_VAR)(2,6) 6 | PsiElement(ID)('true')(2,6) 7 | PsiWhiteSpace('\n')(6,7) 8 | NixExprVarImpl(EXPR_VAR)(7,12) 9 | PsiElement(ID)('false')(7,12) 10 | PsiWhiteSpace('\n')(12,13) 11 | PsiElement(])(']')(13,14) 12 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Function.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | ( ('(') 4 | ID ('x') 5 | : (':') 6 | WHITE_SPACE (' ') 7 | ID ('x') 8 | ) (')') 9 | WHITE_SPACE ('\n') 10 | ( ('(') 11 | ID ('x') 12 | : (':') 13 | WHITE_SPACE (' ') 14 | ID ('y') 15 | : (':') 16 | WHITE_SPACE (' ') 17 | ID ('x') 18 | WHITE_SPACE (' ') 19 | + ('+') 20 | WHITE_SPACE (' ') 21 | ID ('y') 22 | ) (')') 23 | WHITE_SPACE ('\n') 24 | ( ('(') 25 | { ('{') 26 | WHITE_SPACE (' ') 27 | ID ('x') 28 | , (',') 29 | WHITE_SPACE (' ') 30 | ID ('y') 31 | WHITE_SPACE (' ') 32 | } ('}') 33 | : (':') 34 | WHITE_SPACE (' ') 35 | ID ('x') 36 | WHITE_SPACE (' ') 37 | + ('+') 38 | WHITE_SPACE (' ') 39 | ID ('y') 40 | ) (')') 41 | WHITE_SPACE ('\n') 42 | ( ('(') 43 | { ('{') 44 | WHITE_SPACE (' ') 45 | ID ('x') 46 | , (',') 47 | WHITE_SPACE (' ') 48 | ID ('y') 49 | , (',') 50 | WHITE_SPACE (' ') 51 | ... ('...') 52 | WHITE_SPACE (' ') 53 | } ('}') 54 | : (':') 55 | WHITE_SPACE (' ') 56 | ID ('x') 57 | WHITE_SPACE (' ') 58 | + ('+') 59 | WHITE_SPACE (' ') 60 | ID ('y') 61 | ) (')') 62 | WHITE_SPACE ('\n') 63 | ( ('(') 64 | { ('{') 65 | WHITE_SPACE (' ') 66 | ID ('x') 67 | WHITE_SPACE (' ') 68 | ? ('?') 69 | WHITE_SPACE (' ') 70 | STRING_OPEN ('"') 71 | STR ('default') 72 | STRING_CLOSE ('"') 73 | WHITE_SPACE (' ') 74 | } ('}') 75 | WHITE_SPACE (' ') 76 | : (':') 77 | WHITE_SPACE (' ') 78 | ID ('x') 79 | ) (')') 80 | WHITE_SPACE ('\n') 81 | ( ('(') 82 | ID ('args') 83 | @ ('@') 84 | { ('{') 85 | WHITE_SPACE (' ') 86 | ... ('...') 87 | WHITE_SPACE (' ') 88 | } ('}') 89 | : (':') 90 | WHITE_SPACE (' ') 91 | ID ('args') 92 | ) (')') 93 | WHITE_SPACE ('\n') 94 | ( ('(') 95 | { ('{') 96 | WHITE_SPACE (' ') 97 | ... ('...') 98 | WHITE_SPACE (' ') 99 | } ('}') 100 | WHITE_SPACE (' ') 101 | @ ('@') 102 | WHITE_SPACE (' ') 103 | ID ('args') 104 | : (':') 105 | WHITE_SPACE (' ') 106 | ID ('args') 107 | ) (')') 108 | WHITE_SPACE ('\n') 109 | ] (']') 110 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Function.nix: -------------------------------------------------------------------------------- 1 | [ 2 | (x: x) 3 | (x: y: x + y) 4 | ({ x, y }: x + y) 5 | ({ x, y, ... }: x + y) 6 | ({ x ? "default" } : x) 7 | (args@{ ... }: args) 8 | ({ ... } @ args: args) 9 | ] 10 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/FunctionEmptySet.lexer.txt: -------------------------------------------------------------------------------- 1 | { ('{') 2 | WHITE_SPACE (' ') 3 | } ('}') 4 | : (':') 5 | WHITE_SPACE (' ') 6 | ID ('null') 7 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/FunctionEmptySet.nix: -------------------------------------------------------------------------------- 1 | { }: null 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/FunctionEmptySet.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,9) 2 | NixExprLambdaImpl(EXPR_LAMBDA)(0,9) 3 | NixFormalsImpl(FORMALS)(0,3) 4 | PsiElement({)('{')(0,1) 5 | PsiWhiteSpace(' ')(1,2) 6 | PsiElement(})('}')(2,3) 7 | PsiElement(:)(':')(3,4) 8 | PsiWhiteSpace(' ')(4,5) 9 | NixExprVarImpl(EXPR_VAR)(5,9) 10 | PsiElement(ID)('null')(5,9) 11 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/FunctionTrailingComma.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | ( ('(') 4 | { ('{') 5 | WHITE_SPACE (' ') 6 | ID ('x') 7 | , (',') 8 | WHITE_SPACE (' ') 9 | } ('}') 10 | : (':') 11 | WHITE_SPACE (' ') 12 | ID ('null') 13 | ) (')') 14 | WHITE_SPACE ('\n') 15 | ( ('(') 16 | { ('{') 17 | WHITE_SPACE (' ') 18 | ID ('x') 19 | , (',') 20 | WHITE_SPACE (' ') 21 | ID ('y') 22 | , (',') 23 | WHITE_SPACE (' ') 24 | } ('}') 25 | : (':') 26 | WHITE_SPACE (' ') 27 | ID ('null') 28 | ) (')') 29 | WHITE_SPACE ('\n') 30 | ( ('(') 31 | { ('{') 32 | WHITE_SPACE (' ') 33 | ID ('x') 34 | WHITE_SPACE (' ') 35 | ? ('?') 36 | WHITE_SPACE (' ') 37 | ID ('null') 38 | , (',') 39 | WHITE_SPACE (' ') 40 | } ('}') 41 | : (':') 42 | WHITE_SPACE (' ') 43 | ID ('null') 44 | ) (')') 45 | WHITE_SPACE ('\n') 46 | ] (']') 47 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/FunctionTrailingComma.nix: -------------------------------------------------------------------------------- 1 | [ 2 | ({ x, }: null) 3 | ({ x, y, }: null) 4 | ({ x ? null, }: null) 5 | ] 6 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/FunctionTrailingComma.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,58) 2 | NixExprListImpl(EXPR_LIST)(0,58) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace('\n')(1,2) 5 | NixExprParensImpl(EXPR_PARENS)(2,16) 6 | PsiElement(()('(')(2,3) 7 | NixExprLambdaImpl(EXPR_LAMBDA)(3,15) 8 | NixFormalsImpl(FORMALS)(3,9) 9 | PsiElement({)('{')(3,4) 10 | PsiWhiteSpace(' ')(4,5) 11 | NixFormalImpl(FORMAL)(5,6) 12 | NixParameterNameImpl(PARAMETER_NAME)(5,6) 13 | PsiElement(ID)('x')(5,6) 14 | PsiElement(,)(',')(6,7) 15 | PsiWhiteSpace(' ')(7,8) 16 | PsiElement(})('}')(8,9) 17 | PsiElement(:)(':')(9,10) 18 | PsiWhiteSpace(' ')(10,11) 19 | NixExprVarImpl(EXPR_VAR)(11,15) 20 | PsiElement(ID)('null')(11,15) 21 | PsiElement())(')')(15,16) 22 | PsiWhiteSpace('\n')(16,17) 23 | NixExprParensImpl(EXPR_PARENS)(17,34) 24 | PsiElement(()('(')(17,18) 25 | NixExprLambdaImpl(EXPR_LAMBDA)(18,33) 26 | NixFormalsImpl(FORMALS)(18,27) 27 | PsiElement({)('{')(18,19) 28 | PsiWhiteSpace(' ')(19,20) 29 | NixFormalImpl(FORMAL)(20,21) 30 | NixParameterNameImpl(PARAMETER_NAME)(20,21) 31 | PsiElement(ID)('x')(20,21) 32 | PsiElement(,)(',')(21,22) 33 | PsiWhiteSpace(' ')(22,23) 34 | NixFormalImpl(FORMAL)(23,24) 35 | NixParameterNameImpl(PARAMETER_NAME)(23,24) 36 | PsiElement(ID)('y')(23,24) 37 | PsiElement(,)(',')(24,25) 38 | PsiWhiteSpace(' ')(25,26) 39 | PsiElement(})('}')(26,27) 40 | PsiElement(:)(':')(27,28) 41 | PsiWhiteSpace(' ')(28,29) 42 | NixExprVarImpl(EXPR_VAR)(29,33) 43 | PsiElement(ID)('null')(29,33) 44 | PsiElement())(')')(33,34) 45 | PsiWhiteSpace('\n')(34,35) 46 | NixExprParensImpl(EXPR_PARENS)(35,56) 47 | PsiElement(()('(')(35,36) 48 | NixExprLambdaImpl(EXPR_LAMBDA)(36,55) 49 | NixFormalsImpl(FORMALS)(36,49) 50 | PsiElement({)('{')(36,37) 51 | PsiWhiteSpace(' ')(37,38) 52 | NixFormalImpl(FORMAL)(38,46) 53 | NixParameterNameImpl(PARAMETER_NAME)(38,39) 54 | PsiElement(ID)('x')(38,39) 55 | PsiWhiteSpace(' ')(39,40) 56 | PsiElement(?)('?')(40,41) 57 | PsiWhiteSpace(' ')(41,42) 58 | NixExprVarImpl(EXPR_VAR)(42,46) 59 | PsiElement(ID)('null')(42,46) 60 | PsiElement(,)(',')(46,47) 61 | PsiWhiteSpace(' ')(47,48) 62 | PsiElement(})('}')(48,49) 63 | PsiElement(:)(':')(49,50) 64 | PsiWhiteSpace(' ')(50,51) 65 | NixExprVarImpl(EXPR_VAR)(51,55) 66 | PsiElement(ID)('null')(51,55) 67 | PsiElement())(')')(55,56) 68 | PsiWhiteSpace('\n')(56,57) 69 | PsiElement(])(']')(57,58) 70 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Identifier.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | ID ('_') 4 | WHITE_SPACE ('\n') 5 | ID ('A') 6 | WHITE_SPACE ('\n') 7 | ID ('a-0'') 8 | WHITE_SPACE ('\n') 9 | ] (']') 10 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Identifier.nix: -------------------------------------------------------------------------------- 1 | [ 2 | _ 3 | A 4 | a-0' 5 | ] 6 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Identifier.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,12) 2 | NixExprListImpl(EXPR_LIST)(0,12) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace('\n')(1,2) 5 | NixExprVarImpl(EXPR_VAR)(2,3) 6 | PsiElement(ID)('_')(2,3) 7 | PsiWhiteSpace('\n')(3,4) 8 | NixExprVarImpl(EXPR_VAR)(4,5) 9 | PsiElement(ID)('A')(4,5) 10 | PsiWhiteSpace('\n')(5,6) 11 | NixExprVarImpl(EXPR_VAR)(6,10) 12 | PsiElement(ID)('a-0'')(6,10) 13 | PsiWhiteSpace('\n')(10,11) 14 | PsiElement(])(']')(11,12) 15 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/If.lexer.txt: -------------------------------------------------------------------------------- 1 | ⁠if ('if') 2 | WHITE_SPACE (' ') 3 | ID ('e1') 4 | WHITE_SPACE (' ') 5 | ⁠then ('then') 6 | WHITE_SPACE (' ') 7 | ID ('e2') 8 | WHITE_SPACE (' ') 9 | ⁠else ('else') 10 | WHITE_SPACE (' ') 11 | ID ('e3') 12 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/If.nix: -------------------------------------------------------------------------------- 1 | if e1 then e2 else e3 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/If.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,21) 2 | NixExprIfImpl(EXPR_IF)(0,21) 3 | PsiElement(⁠if)('if')(0,2) 4 | PsiWhiteSpace(' ')(2,3) 5 | NixExprVarImpl(EXPR_VAR)(3,5) 6 | PsiElement(ID)('e1')(3,5) 7 | PsiWhiteSpace(' ')(5,6) 8 | PsiElement(⁠then)('then')(6,10) 9 | PsiWhiteSpace(' ')(10,11) 10 | NixExprVarImpl(EXPR_VAR)(11,13) 11 | PsiElement(ID)('e2')(11,13) 12 | PsiWhiteSpace(' ')(13,14) 13 | PsiElement(⁠else)('else')(14,18) 14 | PsiWhiteSpace(' ')(18,19) 15 | NixExprVarImpl(EXPR_VAR)(19,21) 16 | PsiElement(ID)('e3')(19,21) 17 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyLet.lexer.txt: -------------------------------------------------------------------------------- 1 | ⁠let ('let') 2 | WHITE_SPACE (' ') 3 | { ('{') 4 | WHITE_SPACE (' ') 5 | ID ('x') 6 | WHITE_SPACE (' ') 7 | = ('=') 8 | WHITE_SPACE (' ') 9 | INT ('1') 10 | ; (';') 11 | WHITE_SPACE (' ') 12 | ID ('body') 13 | WHITE_SPACE (' ') 14 | = ('=') 15 | WHITE_SPACE (' ') 16 | ID ('x') 17 | ; (';') 18 | WHITE_SPACE (' ') 19 | } ('}') 20 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyLet.nix: -------------------------------------------------------------------------------- 1 | let { x = 1; body = x; } 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyLet.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,24) 2 | NixExprAttrsImpl(EXPR_ATTRS)(0,24) 3 | PsiElement(⁠let)('let')(0,3) 4 | PsiWhiteSpace(' ')(3,4) 5 | PsiElement({)('{')(4,5) 6 | PsiWhiteSpace(' ')(5,6) 7 | NixBindAttrImpl(BIND_ATTR)(6,12) 8 | NixAttrPathImpl(ATTR_PATH)(6,7) 9 | NixStdAttrImpl(STD_ATTR)(6,7) 10 | PsiElement(ID)('x')(6,7) 11 | PsiWhiteSpace(' ')(7,8) 12 | PsiElement(=)('=')(8,9) 13 | PsiWhiteSpace(' ')(9,10) 14 | NixExprIntImpl(EXPR_INT)(10,11) 15 | PsiElement(INT)('1')(10,11) 16 | PsiElement(;)(';')(11,12) 17 | PsiWhiteSpace(' ')(12,13) 18 | NixBindAttrImpl(BIND_ATTR)(13,22) 19 | NixAttrPathImpl(ATTR_PATH)(13,17) 20 | NixStdAttrImpl(STD_ATTR)(13,17) 21 | PsiElement(ID)('body')(13,17) 22 | PsiWhiteSpace(' ')(17,18) 23 | PsiElement(=)('=')(18,19) 24 | PsiWhiteSpace(' ')(19,20) 25 | NixExprVarImpl(EXPR_VAR)(20,21) 26 | PsiElement(ID)('x')(20,21) 27 | PsiElement(;)(';')(21,22) 28 | PsiWhiteSpace(' ')(22,23) 29 | PsiElement(})('}')(23,24) 30 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyLetInList.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE (' ') 3 | ⁠let ('let') 4 | WHITE_SPACE (' ') 5 | { ('{') 6 | WHITE_SPACE (' ') 7 | ID ('x') 8 | WHITE_SPACE (' ') 9 | = ('=') 10 | WHITE_SPACE (' ') 11 | INT ('1') 12 | ; (';') 13 | WHITE_SPACE (' ') 14 | ID ('body') 15 | WHITE_SPACE (' ') 16 | = ('=') 17 | WHITE_SPACE (' ') 18 | ID ('x') 19 | ; (';') 20 | WHITE_SPACE (' ') 21 | } ('}') 22 | WHITE_SPACE (' ') 23 | ] (']') 24 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyLetInList.nix: -------------------------------------------------------------------------------- 1 | [ let { x = 1; body = x; } ] 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyLetInList.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,28) 2 | NixExprListImpl(EXPR_LIST)(0,28) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace(' ')(1,2) 5 | NixExprAttrsImpl(EXPR_ATTRS)(2,26) 6 | PsiElement(⁠let)('let')(2,5) 7 | PsiWhiteSpace(' ')(5,6) 8 | PsiElement({)('{')(6,7) 9 | PsiWhiteSpace(' ')(7,8) 10 | NixBindAttrImpl(BIND_ATTR)(8,14) 11 | NixAttrPathImpl(ATTR_PATH)(8,9) 12 | NixStdAttrImpl(STD_ATTR)(8,9) 13 | PsiElement(ID)('x')(8,9) 14 | PsiWhiteSpace(' ')(9,10) 15 | PsiElement(=)('=')(10,11) 16 | PsiWhiteSpace(' ')(11,12) 17 | NixExprIntImpl(EXPR_INT)(12,13) 18 | PsiElement(INT)('1')(12,13) 19 | PsiElement(;)(';')(13,14) 20 | PsiWhiteSpace(' ')(14,15) 21 | NixBindAttrImpl(BIND_ATTR)(15,24) 22 | NixAttrPathImpl(ATTR_PATH)(15,19) 23 | NixStdAttrImpl(STD_ATTR)(15,19) 24 | PsiElement(ID)('body')(15,19) 25 | PsiWhiteSpace(' ')(19,20) 26 | PsiElement(=)('=')(20,21) 27 | PsiWhiteSpace(' ')(21,22) 28 | NixExprVarImpl(EXPR_VAR)(22,23) 29 | PsiElement(ID)('x')(22,23) 30 | PsiElement(;)(';')(23,24) 31 | PsiWhiteSpace(' ')(24,25) 32 | PsiElement(})('}')(25,26) 33 | PsiWhiteSpace(' ')(26,27) 34 | PsiElement(])(']')(27,28) 35 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyOrAsArgument.lexer.txt: -------------------------------------------------------------------------------- 1 | ID ('f') 2 | WHITE_SPACE (' ') 3 | ⁠or ('or') 4 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyOrAsArgument.nix: -------------------------------------------------------------------------------- 1 | f or 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyOrAsArgument.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,4) 2 | NixLegacyAppOrImpl(LEGACY_APP_OR)(0,4) 3 | NixExprVarImpl(EXPR_VAR)(0,1) 4 | PsiElement(ID)('f')(0,1) 5 | PsiWhiteSpace(' ')(1,2) 6 | PsiElement(⁠or)('or')(2,4) 7 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyOrAsAttribute.lexer.txt: -------------------------------------------------------------------------------- 1 | ⁠let ('let') 2 | WHITE_SPACE (' ') 3 | ⁠or ('or') 4 | WHITE_SPACE (' ') 5 | = ('=') 6 | WHITE_SPACE (' ') 7 | INT ('1') 8 | ; (';') 9 | WHITE_SPACE (' ') 10 | ⁠in ('in') 11 | WHITE_SPACE (' ') 12 | { ('{') 13 | WHITE_SPACE (' ') 14 | ⁠inherit ('inherit') 15 | WHITE_SPACE (' ') 16 | ⁠or ('or') 17 | ; (';') 18 | WHITE_SPACE (' ') 19 | } ('}') 20 | . ('.') 21 | ⁠or ('or') 22 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyOrAsAttribute.nix: -------------------------------------------------------------------------------- 1 | let or = 1; in { inherit or; }.or 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyOrAsAttribute.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,33) 2 | NixExprLetImpl(EXPR_LET)(0,33) 3 | PsiElement(⁠let)('let')(0,3) 4 | PsiWhiteSpace(' ')(3,4) 5 | NixBindAttrImpl(BIND_ATTR)(4,11) 6 | NixAttrPathImpl(ATTR_PATH)(4,6) 7 | NixStdAttrImpl(STD_ATTR)(4,6) 8 | PsiElement(⁠or)('or')(4,6) 9 | PsiWhiteSpace(' ')(6,7) 10 | PsiElement(=)('=')(7,8) 11 | PsiWhiteSpace(' ')(8,9) 12 | NixExprIntImpl(EXPR_INT)(9,10) 13 | PsiElement(INT)('1')(9,10) 14 | PsiElement(;)(';')(10,11) 15 | PsiWhiteSpace(' ')(11,12) 16 | PsiElement(⁠in)('in')(12,14) 17 | PsiWhiteSpace(' ')(14,15) 18 | NixExprSelectImpl(EXPR_SELECT)(15,33) 19 | NixExprAttrsImpl(EXPR_ATTRS)(15,30) 20 | PsiElement({)('{')(15,16) 21 | PsiWhiteSpace(' ')(16,17) 22 | NixBindInheritImpl(BIND_INHERIT)(17,28) 23 | PsiElement(⁠inherit)('inherit')(17,24) 24 | PsiWhiteSpace(' ')(24,25) 25 | NixStdAttrImpl(STD_ATTR)(25,27) 26 | PsiElement(⁠or)('or')(25,27) 27 | PsiElement(;)(';')(27,28) 28 | PsiWhiteSpace(' ')(28,29) 29 | PsiElement(})('}')(29,30) 30 | PsiElement(.)('.')(30,31) 31 | NixAttrPathImpl(ATTR_PATH)(31,33) 32 | NixStdAttrImpl(STD_ATTR)(31,33) 33 | PsiElement(⁠or)('or')(31,33) 34 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyOrInList.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE (' ') 3 | ID ('before') 4 | WHITE_SPACE (' ') 5 | ID ('f') 6 | WHITE_SPACE (' ') 7 | ⁠or ('or') 8 | WHITE_SPACE (' ') 9 | ID ('after') 10 | WHITE_SPACE (' ') 11 | ] (']') 12 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyOrInList.nix: -------------------------------------------------------------------------------- 1 | [ before f or after ] 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LegacyOrInList.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,21) 2 | NixExprListImpl(EXPR_LIST)(0,21) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace(' ')(1,2) 5 | NixExprVarImpl(EXPR_VAR)(2,8) 6 | PsiElement(ID)('before')(2,8) 7 | PsiWhiteSpace(' ')(8,9) 8 | NixLegacyAppOrImpl(LEGACY_APP_OR)(9,13) 9 | NixExprVarImpl(EXPR_VAR)(9,10) 10 | PsiElement(ID)('f')(9,10) 11 | PsiWhiteSpace(' ')(10,11) 12 | PsiElement(⁠or)('or')(11,13) 13 | PsiWhiteSpace(' ')(13,14) 14 | NixExprVarImpl(EXPR_VAR)(14,19) 15 | PsiElement(ID)('after')(14,19) 16 | PsiWhiteSpace(' ')(19,20) 17 | PsiElement(])(']')(20,21) 18 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Let.lexer.txt: -------------------------------------------------------------------------------- 1 | ⁠let ('let') 2 | WHITE_SPACE ('\n ') 3 | ID ('x') 4 | WHITE_SPACE (' ') 5 | = ('=') 6 | WHITE_SPACE (' ') 7 | STRING_OPEN ('"') 8 | STR ('foo') 9 | STRING_CLOSE ('"') 10 | ; (';') 11 | WHITE_SPACE ('\n ') 12 | ID ('a') 13 | . ('.') 14 | ID ('b') 15 | WHITE_SPACE (' ') 16 | = ('=') 17 | WHITE_SPACE (' ') 18 | STRING_OPEN ('"') 19 | STR ('bar') 20 | STRING_CLOSE ('"') 21 | ; (';') 22 | WHITE_SPACE ('\n') 23 | ⁠in ('in') 24 | WHITE_SPACE (' ') 25 | ID ('x') 26 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Let.nix: -------------------------------------------------------------------------------- 1 | let 2 | x = "foo"; 3 | a.b = "bar"; 4 | in x 5 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Let.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,36) 2 | NixExprLetImpl(EXPR_LET)(0,36) 3 | PsiElement(⁠let)('let')(0,3) 4 | PsiWhiteSpace('\n ')(3,6) 5 | NixBindAttrImpl(BIND_ATTR)(6,16) 6 | NixAttrPathImpl(ATTR_PATH)(6,7) 7 | NixStdAttrImpl(STD_ATTR)(6,7) 8 | PsiElement(ID)('x')(6,7) 9 | PsiWhiteSpace(' ')(7,8) 10 | PsiElement(=)('=')(8,9) 11 | PsiWhiteSpace(' ')(9,10) 12 | NixStdStringImpl(STD_STRING)(10,15) 13 | PsiElement(STRING_OPEN)('"')(10,11) 14 | NixStringTextImpl(STRING_TEXT)(11,14) 15 | PsiElement(STR)('foo')(11,14) 16 | PsiElement(STRING_CLOSE)('"')(14,15) 17 | PsiElement(;)(';')(15,16) 18 | PsiWhiteSpace('\n ')(16,19) 19 | NixBindAttrImpl(BIND_ATTR)(19,31) 20 | NixAttrPathImpl(ATTR_PATH)(19,22) 21 | NixStdAttrImpl(STD_ATTR)(19,20) 22 | PsiElement(ID)('a')(19,20) 23 | PsiElement(.)('.')(20,21) 24 | NixStdAttrImpl(STD_ATTR)(21,22) 25 | PsiElement(ID)('b')(21,22) 26 | PsiWhiteSpace(' ')(22,23) 27 | PsiElement(=)('=')(23,24) 28 | PsiWhiteSpace(' ')(24,25) 29 | NixStdStringImpl(STD_STRING)(25,30) 30 | PsiElement(STRING_OPEN)('"')(25,26) 31 | NixStringTextImpl(STRING_TEXT)(26,29) 32 | PsiElement(STR)('bar')(26,29) 33 | PsiElement(STRING_CLOSE)('"')(29,30) 34 | PsiElement(;)(';')(30,31) 35 | PsiWhiteSpace('\n')(31,32) 36 | PsiElement(⁠in)('in')(32,34) 37 | PsiWhiteSpace(' ')(34,35) 38 | NixExprVarImpl(EXPR_VAR)(35,36) 39 | PsiElement(ID)('x')(35,36) 40 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LetEmpty.lexer.txt: -------------------------------------------------------------------------------- 1 | ⁠let ('let') 2 | WHITE_SPACE (' ') 3 | ⁠in ('in') 4 | WHITE_SPACE (' ') 5 | ID ('x') 6 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LetEmpty.nix: -------------------------------------------------------------------------------- 1 | let in x 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/LetEmpty.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,8) 2 | NixExprLetImpl(EXPR_LET)(0,8) 3 | PsiElement(⁠let)('let')(0,3) 4 | PsiWhiteSpace(' ')(3,4) 5 | PsiElement(⁠in)('in')(4,6) 6 | PsiWhiteSpace(' ')(6,7) 7 | NixExprVarImpl(EXPR_VAR)(7,8) 8 | PsiElement(ID)('x')(7,8) 9 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/List.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE (' ') 3 | INT ('123') 4 | WHITE_SPACE (' ') 5 | PATH_SEGMENT ('./foo.nix') 6 | PATH_END ('') 7 | WHITE_SPACE (' ') 8 | STRING_OPEN ('"') 9 | STR ('abc') 10 | STRING_CLOSE ('"') 11 | WHITE_SPACE (' ') 12 | ID ('f') 13 | WHITE_SPACE (' ') 14 | { ('{') 15 | WHITE_SPACE (' ') 16 | ID ('x') 17 | WHITE_SPACE (' ') 18 | = ('=') 19 | WHITE_SPACE (' ') 20 | ID ('y') 21 | ; (';') 22 | WHITE_SPACE (' ') 23 | } ('}') 24 | WHITE_SPACE (' ') 25 | ] (']') 26 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/List.nix: -------------------------------------------------------------------------------- 1 | [ 123 ./foo.nix "abc" f { x = y; } ] 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/List.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,36) 2 | NixExprListImpl(EXPR_LIST)(0,36) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace(' ')(1,2) 5 | NixExprIntImpl(EXPR_INT)(2,5) 6 | PsiElement(INT)('123')(2,5) 7 | PsiWhiteSpace(' ')(5,6) 8 | NixExprStdPathImpl(EXPR_STD_PATH)(6,15) 9 | PsiElement(PATH_SEGMENT)('./foo.nix')(6,15) 10 | PsiWhiteSpace(' ')(15,16) 11 | NixStdStringImpl(STD_STRING)(16,21) 12 | PsiElement(STRING_OPEN)('"')(16,17) 13 | NixStringTextImpl(STRING_TEXT)(17,20) 14 | PsiElement(STR)('abc')(17,20) 15 | PsiElement(STRING_CLOSE)('"')(20,21) 16 | PsiWhiteSpace(' ')(21,22) 17 | NixExprVarImpl(EXPR_VAR)(22,23) 18 | PsiElement(ID)('f')(22,23) 19 | PsiWhiteSpace(' ')(23,24) 20 | NixExprAttrsImpl(EXPR_ATTRS)(24,34) 21 | PsiElement({)('{')(24,25) 22 | PsiWhiteSpace(' ')(25,26) 23 | NixBindAttrImpl(BIND_ATTR)(26,32) 24 | NixAttrPathImpl(ATTR_PATH)(26,27) 25 | NixStdAttrImpl(STD_ATTR)(26,27) 26 | PsiElement(ID)('x')(26,27) 27 | PsiWhiteSpace(' ')(27,28) 28 | PsiElement(=)('=')(28,29) 29 | PsiWhiteSpace(' ')(29,30) 30 | NixExprVarImpl(EXPR_VAR)(30,31) 31 | PsiElement(ID)('y')(30,31) 32 | PsiElement(;)(';')(31,32) 33 | PsiWhiteSpace(' ')(32,33) 34 | PsiElement(})('}')(33,34) 35 | PsiWhiteSpace(' ')(34,35) 36 | PsiElement(])(']')(35,36) 37 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/ListWithFunction.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE (' ') 3 | INT ('123') 4 | WHITE_SPACE (' ') 5 | PATH_SEGMENT ('./foo.nix') 6 | PATH_END ('') 7 | WHITE_SPACE (' ') 8 | STRING_OPEN ('"') 9 | STR ('abc') 10 | STRING_CLOSE ('"') 11 | WHITE_SPACE (' ') 12 | ( ('(') 13 | ID ('f') 14 | WHITE_SPACE (' ') 15 | { ('{') 16 | WHITE_SPACE (' ') 17 | ID ('x') 18 | WHITE_SPACE (' ') 19 | = ('=') 20 | WHITE_SPACE (' ') 21 | ID ('y') 22 | ; (';') 23 | WHITE_SPACE (' ') 24 | } ('}') 25 | ) (')') 26 | WHITE_SPACE (' ') 27 | ] (']') 28 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/ListWithFunction.nix: -------------------------------------------------------------------------------- 1 | [ 123 ./foo.nix "abc" (f { x = y; }) ] 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/ListWithFunction.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,38) 2 | NixExprListImpl(EXPR_LIST)(0,38) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace(' ')(1,2) 5 | NixExprIntImpl(EXPR_INT)(2,5) 6 | PsiElement(INT)('123')(2,5) 7 | PsiWhiteSpace(' ')(5,6) 8 | NixExprStdPathImpl(EXPR_STD_PATH)(6,15) 9 | PsiElement(PATH_SEGMENT)('./foo.nix')(6,15) 10 | PsiWhiteSpace(' ')(15,16) 11 | NixStdStringImpl(STD_STRING)(16,21) 12 | PsiElement(STRING_OPEN)('"')(16,17) 13 | NixStringTextImpl(STRING_TEXT)(17,20) 14 | PsiElement(STR)('abc')(17,20) 15 | PsiElement(STRING_CLOSE)('"')(20,21) 16 | PsiWhiteSpace(' ')(21,22) 17 | NixExprParensImpl(EXPR_PARENS)(22,36) 18 | PsiElement(()('(')(22,23) 19 | NixExprAppImpl(EXPR_APP)(23,35) 20 | NixExprVarImpl(EXPR_VAR)(23,24) 21 | PsiElement(ID)('f')(23,24) 22 | PsiWhiteSpace(' ')(24,25) 23 | NixExprAttrsImpl(EXPR_ATTRS)(25,35) 24 | PsiElement({)('{')(25,26) 25 | PsiWhiteSpace(' ')(26,27) 26 | NixBindAttrImpl(BIND_ATTR)(27,33) 27 | NixAttrPathImpl(ATTR_PATH)(27,28) 28 | NixStdAttrImpl(STD_ATTR)(27,28) 29 | PsiElement(ID)('x')(27,28) 30 | PsiWhiteSpace(' ')(28,29) 31 | PsiElement(=)('=')(29,30) 32 | PsiWhiteSpace(' ')(30,31) 33 | NixExprVarImpl(EXPR_VAR)(31,32) 34 | PsiElement(ID)('y')(31,32) 35 | PsiElement(;)(';')(32,33) 36 | PsiWhiteSpace(' ')(33,34) 37 | PsiElement(})('}')(34,35) 38 | PsiElement())(')')(35,36) 39 | PsiWhiteSpace(' ')(36,37) 40 | PsiElement(])(']')(37,38) 41 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Null.lexer.txt: -------------------------------------------------------------------------------- 1 | ID ('null') 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Null.nix: -------------------------------------------------------------------------------- 1 | null 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Null.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,4) 2 | NixExprVarImpl(EXPR_VAR)(0,4) 3 | PsiElement(ID)('null')(0,4) 4 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Number.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | INT ('123') 4 | WHITE_SPACE ('\n') 5 | FLOAT ('123.43') 6 | WHITE_SPACE ('\n') 7 | FLOAT ('.27e13') 8 | WHITE_SPACE ('\n') 9 | ] (']') 10 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Number.nix: -------------------------------------------------------------------------------- 1 | [ 2 | 123 3 | 123.43 4 | .27e13 5 | ] 6 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Number.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,21) 2 | NixExprListImpl(EXPR_LIST)(0,21) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace('\n')(1,2) 5 | NixExprIntImpl(EXPR_INT)(2,5) 6 | PsiElement(INT)('123')(2,5) 7 | PsiWhiteSpace('\n')(5,6) 8 | NixExprFloatImpl(EXPR_FLOAT)(6,12) 9 | PsiElement(FLOAT)('123.43')(6,12) 10 | PsiWhiteSpace('\n')(12,13) 11 | NixExprFloatImpl(EXPR_FLOAT)(13,19) 12 | PsiElement(FLOAT)('.27e13')(13,19) 13 | PsiWhiteSpace('\n')(19,20) 14 | PsiElement(])(']')(20,21) 15 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Operators.nix: -------------------------------------------------------------------------------- 1 | [ 2 | (e.attrpath) 3 | (e.attrpath or def) 4 | (e1.attrpath e2.attrpath) 5 | (-e1 e2) 6 | (-e ? attrpath) 7 | (e1 ? attrpath ++ e2 ? attrpath) 8 | (e11 ++ e12 * e21 ++ e22) 9 | (e11 ++ e12 / e21 ++ e22) 10 | (e11 * e12 + e21 / e22) 11 | (e11 / e12 - e21 * e22) 12 | (!e1 + e2) 13 | (!e1 // !e2) 14 | (e11 // e12 < e21 // e22) 15 | (e11 // e12 <= e21 // e22) 16 | (e11 // e12 > e21 // e22) 17 | (e11 // e12 >= e21 // e22) 18 | (e11 < e12 == e21 <= e22) 19 | (e11 > e12 != e21 >= e22) 20 | (e11 == e12 && e21 != e22) 21 | (e11 && e12 || e21 && e22) 22 | (e11 || e12 -> e21 || e22) 23 | ] 24 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/OperatorsAssociativity.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | ( ('(') 4 | ID ('a') 5 | WHITE_SPACE (' ') 6 | ID ('b') 7 | WHITE_SPACE (' ') 8 | ID ('c') 9 | ) (')') 10 | WHITE_SPACE ('\n') 11 | ( ('(') 12 | ID ('a') 13 | WHITE_SPACE (' ') 14 | ++ ('++') 15 | WHITE_SPACE (' ') 16 | ID ('b') 17 | WHITE_SPACE (' ') 18 | ++ ('++') 19 | WHITE_SPACE (' ') 20 | ID ('c') 21 | ) (')') 22 | WHITE_SPACE ('\n') 23 | ( ('(') 24 | ID ('a') 25 | WHITE_SPACE (' ') 26 | * ('*') 27 | WHITE_SPACE (' ') 28 | ID ('b') 29 | WHITE_SPACE (' ') 30 | / ('/') 31 | WHITE_SPACE (' ') 32 | ID ('c') 33 | WHITE_SPACE (' ') 34 | * ('*') 35 | WHITE_SPACE (' ') 36 | ID ('d') 37 | ) (')') 38 | WHITE_SPACE ('\n') 39 | ( ('(') 40 | ID ('a') 41 | WHITE_SPACE (' ') 42 | + ('+') 43 | WHITE_SPACE (' ') 44 | ID ('b') 45 | WHITE_SPACE (' ') 46 | - ('-') 47 | WHITE_SPACE (' ') 48 | ID ('c') 49 | WHITE_SPACE (' ') 50 | + ('+') 51 | WHITE_SPACE (' ') 52 | ID ('d') 53 | ) (')') 54 | WHITE_SPACE ('\n') 55 | ( ('(') 56 | ID ('a') 57 | WHITE_SPACE (' ') 58 | // ('//') 59 | WHITE_SPACE (' ') 60 | ID ('b') 61 | WHITE_SPACE (' ') 62 | // ('//') 63 | WHITE_SPACE (' ') 64 | ID ('c') 65 | ) (')') 66 | WHITE_SPACE ('\n') 67 | ( ('(') 68 | ID ('a') 69 | WHITE_SPACE (' ') 70 | && ('&&') 71 | WHITE_SPACE (' ') 72 | ID ('b') 73 | WHITE_SPACE (' ') 74 | && ('&&') 75 | WHITE_SPACE (' ') 76 | ID ('c') 77 | ) (')') 78 | WHITE_SPACE ('\n') 79 | ( ('(') 80 | ID ('a') 81 | WHITE_SPACE (' ') 82 | || ('||') 83 | WHITE_SPACE (' ') 84 | ID ('b') 85 | WHITE_SPACE (' ') 86 | || ('||') 87 | WHITE_SPACE (' ') 88 | ID ('c') 89 | ) (')') 90 | WHITE_SPACE ('\n') 91 | ] (']') 92 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/OperatorsAssociativity.nix: -------------------------------------------------------------------------------- 1 | [ 2 | (a b c) 3 | (a ++ b ++ c) 4 | (a * b / c * d) 5 | (a + b - c + d) 6 | (a // b // c) 7 | (a && b && c) 8 | (a || b || c) 9 | ] 10 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Path.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | PATH_SEGMENT ('/bin/sh') 4 | PATH_END ('') 5 | WHITE_SPACE ('\n') 6 | PATH_SEGMENT ('./builder.sh') 7 | PATH_END ('') 8 | WHITE_SPACE ('\n') 9 | PATH_SEGMENT ('~/') 10 | PATH_SEGMENT ('foo') 11 | PATH_END ('') 12 | WHITE_SPACE ('\n') 13 | SPATH ('') 14 | WHITE_SPACE ('\n') 15 | SCOMMENT ('# antiquotations') 16 | WHITE_SPACE ('\n') 17 | PATH_SEGMENT ('/') 18 | $ ('$') 19 | { ('{') 20 | ID ('fileName') 21 | } ('}') 22 | PATH_END ('') 23 | WHITE_SPACE ('\n') 24 | PATH_SEGMENT ('/') 25 | $ ('$') 26 | { ('{') 27 | ID ('fileName') 28 | } ('}') 29 | PATH_SEGMENT ('/') 30 | PATH_END ('') 31 | WHITE_SPACE ('\n') 32 | PATH_SEGMENT ('./') 33 | $ ('$') 34 | { ('{') 35 | ID ('foo') 36 | } ('}') 37 | PATH_SEGMENT ('-') 38 | $ ('$') 39 | { ('{') 40 | ID ('bar') 41 | } ('}') 42 | PATH_SEGMENT ('.nix') 43 | PATH_END ('') 44 | WHITE_SPACE ('\n') 45 | PATH_SEGMENT ('./') 46 | $ ('$') 47 | { ('{') 48 | ID ('foo') 49 | } ('}') 50 | PATH_SEGMENT ('-') 51 | $ ('$') 52 | { ('{') 53 | ID ('bar') 54 | } ('}') 55 | PATH_SEGMENT ('/') 56 | PATH_END ('') 57 | WHITE_SPACE ('\n') 58 | STRING_OPEN ('"') 59 | $ ('$') 60 | { ('{') 61 | PATH_SEGMENT ('./foo.txt') 62 | PATH_END ('') 63 | } ('}') 64 | STRING_CLOSE ('"') 65 | WHITE_SPACE ('\n\n') 66 | SCOMMENT ('# whitespace must not be part of paths') 67 | WHITE_SPACE ('\n') 68 | PATH_SEGMENT ('prefix/dir/file.txt') 69 | PATH_END ('') 70 | WHITE_SPACE (' ') 71 | PATH_SEGMENT ('next/path/element') 72 | PATH_END ('') 73 | WHITE_SPACE ('\n\n') 74 | SCOMMENT ('# At least one slash (/) must appear before any interpolated expression for the result to be recognized as a path.') 75 | WHITE_SPACE ('\n') 76 | PATH_SEGMENT ('a/b') 77 | PATH_END ('') 78 | WHITE_SPACE ('\n\n') 79 | SCOMMENT ('# https://nixos.org/manual/nix/stable/language/values.html#type-path') 80 | WHITE_SPACE ('\n') 81 | SCOMMENT ('# a.${foo}/b.${bar} is a syntactically valid division operation.') 82 | WHITE_SPACE ('\n') 83 | SCOMMENT ('# but the Nix parser seems to handle this differently:') 84 | WHITE_SPACE ('\n') 85 | SCOMMENT ('# https://github.com/NixOS/nix-idea/issues/59#issuecomment-1494786812') 86 | WHITE_SPACE ('\n') 87 | ID ('a') 88 | . ('.') 89 | $ ('$') 90 | { ('{') 91 | ID ('foo') 92 | } ('}') 93 | PATH_SEGMENT ('/b.') 94 | $ ('$') 95 | { ('{') 96 | ID ('bar') 97 | } ('}') 98 | PATH_END ('') 99 | WHITE_SPACE ('\n\n') 100 | SCOMMENT ('# ./a.${foo}/b.${bar} is a path.') 101 | WHITE_SPACE ('\n') 102 | PATH_SEGMENT ('./a.') 103 | $ ('$') 104 | { ('{') 105 | ID ('foo') 106 | } ('}') 107 | PATH_SEGMENT ('/') 108 | PATH_SEGMENT ('b.') 109 | $ ('$') 110 | { ('{') 111 | ID ('bar') 112 | } ('}') 113 | PATH_END ('') 114 | WHITE_SPACE ('\n\n') 115 | SCOMMENT ('# trailing slashes') 116 | WHITE_SPACE ('\n') 117 | PATH_SEGMENT ('/dir/subdir/') 118 | PATH_END ('') 119 | WHITE_SPACE ('\n') 120 | PATH_SEGMENT ('./dir/subdir/') 121 | PATH_END ('') 122 | WHITE_SPACE ('\n') 123 | ] (']') -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Path.nix: -------------------------------------------------------------------------------- 1 | [ 2 | /bin/sh 3 | ./builder.sh 4 | ~/foo 5 | 6 | # antiquotations 7 | /${fileName} 8 | /${fileName}/ 9 | ./${foo}-${bar}.nix 10 | ./${foo}-${bar}/ 11 | "${./foo.txt}" 12 | 13 | # whitespace must not be part of paths 14 | prefix/dir/file.txt next/path/element 15 | 16 | # At least one slash (/) must appear before any interpolated expression for the result to be recognized as a path. 17 | a/b 18 | 19 | # https://nixos.org/manual/nix/stable/language/values.html#type-path 20 | # a.${foo}/b.${bar} is a syntactically valid division operation. 21 | # but the Nix parser seems to handle this differently: 22 | # https://github.com/NixOS/nix-idea/issues/59#issuecomment-1494786812 23 | a.${foo}/b.${bar} 24 | 25 | # ./a.${foo}/b.${bar} is a path. 26 | ./a.${foo}/b.${bar} 27 | 28 | # trailing slashes 29 | /dir/subdir/ 30 | ./dir/subdir/ 31 | ] 32 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/RecursiveSet.lexer.txt: -------------------------------------------------------------------------------- 1 | ⁠rec ('rec') 2 | WHITE_SPACE (' ') 3 | { ('{') 4 | WHITE_SPACE ('\n ') 5 | ID ('x') 6 | WHITE_SPACE (' ') 7 | = ('=') 8 | WHITE_SPACE (' ') 9 | ID ('y') 10 | ; (';') 11 | WHITE_SPACE ('\n ') 12 | ID ('y') 13 | WHITE_SPACE (' ') 14 | = ('=') 15 | WHITE_SPACE (' ') 16 | INT ('123') 17 | ; (';') 18 | WHITE_SPACE ('\n') 19 | } ('}') 20 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/RecursiveSet.nix: -------------------------------------------------------------------------------- 1 | rec { 2 | x = y; 3 | y = 123; 4 | } 5 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/RecursiveSet.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,27) 2 | NixExprAttrsImpl(EXPR_ATTRS)(0,27) 3 | PsiElement(⁠rec)('rec')(0,3) 4 | PsiWhiteSpace(' ')(3,4) 5 | PsiElement({)('{')(4,5) 6 | PsiWhiteSpace('\n ')(5,8) 7 | NixBindAttrImpl(BIND_ATTR)(8,14) 8 | NixAttrPathImpl(ATTR_PATH)(8,9) 9 | NixStdAttrImpl(STD_ATTR)(8,9) 10 | PsiElement(ID)('x')(8,9) 11 | PsiWhiteSpace(' ')(9,10) 12 | PsiElement(=)('=')(10,11) 13 | PsiWhiteSpace(' ')(11,12) 14 | NixExprVarImpl(EXPR_VAR)(12,13) 15 | PsiElement(ID)('y')(12,13) 16 | PsiElement(;)(';')(13,14) 17 | PsiWhiteSpace('\n ')(14,17) 18 | NixBindAttrImpl(BIND_ATTR)(17,25) 19 | NixAttrPathImpl(ATTR_PATH)(17,18) 20 | NixStdAttrImpl(STD_ATTR)(17,18) 21 | PsiElement(ID)('y')(17,18) 22 | PsiWhiteSpace(' ')(18,19) 23 | PsiElement(=)('=')(19,20) 24 | PsiWhiteSpace(' ')(20,21) 25 | NixExprIntImpl(EXPR_INT)(21,24) 26 | PsiElement(INT)('123')(21,24) 27 | PsiElement(;)(';')(24,25) 28 | PsiWhiteSpace('\n')(25,26) 29 | PsiElement(})('}')(26,27) 30 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Set.lexer.txt: -------------------------------------------------------------------------------- 1 | { ('{') 2 | WHITE_SPACE ('\n ') 3 | ID ('x') 4 | WHITE_SPACE (' ') 5 | = ('=') 6 | WHITE_SPACE (' ') 7 | INT ('123') 8 | ; (';') 9 | WHITE_SPACE ('\n ') 10 | ID ('a') 11 | . ('.') 12 | ID ('b') 13 | WHITE_SPACE (' ') 14 | = ('=') 15 | WHITE_SPACE (' ') 16 | INT ('123') 17 | ; (';') 18 | WHITE_SPACE ('\n ') 19 | STRING_OPEN ('"') 20 | STR ('< y >') 21 | STRING_CLOSE ('"') 22 | WHITE_SPACE (' ') 23 | = ('=') 24 | WHITE_SPACE (' ') 25 | STRING_OPEN ('"') 26 | STR ('Hello') 27 | STRING_CLOSE ('"') 28 | ; (';') 29 | WHITE_SPACE ('\n ') 30 | $ ('$') 31 | { ('{') 32 | ID ('key') 33 | } ('}') 34 | WHITE_SPACE (' ') 35 | = ('=') 36 | WHITE_SPACE (' ') 37 | PATH_SEGMENT ('./.') 38 | PATH_END ('') 39 | ; (';') 40 | WHITE_SPACE ('\n ') 41 | ⁠inherit ('inherit') 42 | WHITE_SPACE (' ') 43 | ID ('a') 44 | ; (';') 45 | WHITE_SPACE ('\n ') 46 | ⁠inherit ('inherit') 47 | WHITE_SPACE (' ') 48 | ID ('b') 49 | WHITE_SPACE (' ') 50 | ID ('c') 51 | ; (';') 52 | WHITE_SPACE ('\n ') 53 | ⁠inherit ('inherit') 54 | WHITE_SPACE (' ') 55 | ( ('(') 56 | ID ('src-set') 57 | ) (')') 58 | WHITE_SPACE (' ') 59 | ID ('d') 60 | WHITE_SPACE (' ') 61 | ID ('e') 62 | WHITE_SPACE (' ') 63 | ID ('f') 64 | ; (';') 65 | WHITE_SPACE ('\n') 66 | } ('}') 67 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Set.nix: -------------------------------------------------------------------------------- 1 | { 2 | x = 123; 3 | a.b = 123; 4 | "< y >" = "Hello"; 5 | ${key} = ./.; 6 | inherit a; 7 | inherit b c; 8 | inherit (src-set) d e f; 9 | } 10 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/SetAccess.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | ( ('(') 4 | ID ('s') 5 | . ('.') 6 | ID ('x') 7 | ) (')') 8 | WHITE_SPACE ('\n') 9 | ( ('(') 10 | ID ('s') 11 | . ('.') 12 | ID ('x') 13 | WHITE_SPACE (' ') 14 | ⁠or ('or') 15 | WHITE_SPACE (' ') 16 | STRING_OPEN ('"') 17 | STR ('default') 18 | STRING_CLOSE ('"') 19 | ) (')') 20 | WHITE_SPACE ('\n') 21 | ( ('(') 22 | ID ('s') 23 | . ('.') 24 | STRING_OPEN ('"') 25 | STR ('< y >') 26 | STRING_CLOSE ('"') 27 | ) (')') 28 | WHITE_SPACE ('\n') 29 | ( ('(') 30 | ID ('s') 31 | . ('.') 32 | $ ('$') 33 | { ('{') 34 | ID ('key') 35 | } ('}') 36 | ) (')') 37 | WHITE_SPACE ('\n') 38 | ] (']') 39 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/SetAccess.nix: -------------------------------------------------------------------------------- 1 | [ 2 | (s.x) 3 | (s.x or "default") 4 | (s."< y >") 5 | (s.${key}) 6 | ] 7 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/SetAccess.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,51) 2 | NixExprListImpl(EXPR_LIST)(0,51) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace('\n')(1,2) 5 | NixExprParensImpl(EXPR_PARENS)(2,7) 6 | PsiElement(()('(')(2,3) 7 | NixExprSelectImpl(EXPR_SELECT)(3,6) 8 | NixExprVarImpl(EXPR_VAR)(3,4) 9 | PsiElement(ID)('s')(3,4) 10 | PsiElement(.)('.')(4,5) 11 | NixAttrPathImpl(ATTR_PATH)(5,6) 12 | NixStdAttrImpl(STD_ATTR)(5,6) 13 | PsiElement(ID)('x')(5,6) 14 | PsiElement())(')')(6,7) 15 | PsiWhiteSpace('\n')(7,8) 16 | NixExprParensImpl(EXPR_PARENS)(8,26) 17 | PsiElement(()('(')(8,9) 18 | NixExprSelectImpl(EXPR_SELECT)(9,25) 19 | NixExprVarImpl(EXPR_VAR)(9,10) 20 | PsiElement(ID)('s')(9,10) 21 | PsiElement(.)('.')(10,11) 22 | NixAttrPathImpl(ATTR_PATH)(11,12) 23 | NixStdAttrImpl(STD_ATTR)(11,12) 24 | PsiElement(ID)('x')(11,12) 25 | PsiWhiteSpace(' ')(12,13) 26 | PsiElement(⁠or)('or')(13,15) 27 | PsiWhiteSpace(' ')(15,16) 28 | NixStdStringImpl(STD_STRING)(16,25) 29 | PsiElement(STRING_OPEN)('"')(16,17) 30 | NixStringTextImpl(STRING_TEXT)(17,24) 31 | PsiElement(STR)('default')(17,24) 32 | PsiElement(STRING_CLOSE)('"')(24,25) 33 | PsiElement())(')')(25,26) 34 | PsiWhiteSpace('\n')(26,27) 35 | NixExprParensImpl(EXPR_PARENS)(27,38) 36 | PsiElement(()('(')(27,28) 37 | NixExprSelectImpl(EXPR_SELECT)(28,37) 38 | NixExprVarImpl(EXPR_VAR)(28,29) 39 | PsiElement(ID)('s')(28,29) 40 | PsiElement(.)('.')(29,30) 41 | NixAttrPathImpl(ATTR_PATH)(30,37) 42 | NixStringAttrImpl(STRING_ATTR)(30,37) 43 | NixStdStringImpl(STD_STRING)(30,37) 44 | PsiElement(STRING_OPEN)('"')(30,31) 45 | NixStringTextImpl(STRING_TEXT)(31,36) 46 | PsiElement(STR)('< y >')(31,36) 47 | PsiElement(STRING_CLOSE)('"')(36,37) 48 | PsiElement())(')')(37,38) 49 | PsiWhiteSpace('\n')(38,39) 50 | NixExprParensImpl(EXPR_PARENS)(39,49) 51 | PsiElement(()('(')(39,40) 52 | NixExprSelectImpl(EXPR_SELECT)(40,48) 53 | NixExprVarImpl(EXPR_VAR)(40,41) 54 | PsiElement(ID)('s')(40,41) 55 | PsiElement(.)('.')(41,42) 56 | NixAttrPathImpl(ATTR_PATH)(42,48) 57 | NixStringAttrImpl(STRING_ATTR)(42,48) 58 | NixAntiquotationImpl(ANTIQUOTATION)(42,48) 59 | PsiElement($)('$')(42,43) 60 | PsiElement({)('{')(43,44) 61 | NixExprVarImpl(EXPR_VAR)(44,47) 62 | PsiElement(ID)('key')(44,47) 63 | PsiElement(})('}')(47,48) 64 | PsiElement())(')')(48,49) 65 | PsiWhiteSpace('\n')(49,50) 66 | PsiElement(])(']')(50,51) 67 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/String.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | STRING_OPEN ('"') 4 | STR ('expected') 5 | STRING_CLOSE ('"') 6 | WHITE_SPACE ('\n') 7 | IND_STRING_OPEN ('''') 8 | IND_STR ('expected') 9 | IND_STRING_CLOSE ('''') 10 | WHITE_SPACE ('\n') 11 | ] (']') 12 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/String.nix: -------------------------------------------------------------------------------- 1 | [ 2 | "expected" 3 | ''expected'' 4 | ] 5 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/String.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,27) 2 | NixExprListImpl(EXPR_LIST)(0,27) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace('\n')(1,2) 5 | NixStdStringImpl(STD_STRING)(2,12) 6 | PsiElement(STRING_OPEN)('"')(2,3) 7 | NixStringTextImpl(STRING_TEXT)(3,11) 8 | PsiElement(STR)('expected')(3,11) 9 | PsiElement(STRING_CLOSE)('"')(11,12) 10 | PsiWhiteSpace('\n')(12,13) 11 | NixIndStringImpl(IND_STRING)(13,25) 12 | PsiElement(IND_STRING_OPEN)('''')(13,15) 13 | NixStringTextImpl(STRING_TEXT)(15,23) 14 | PsiElement(IND_STR)('expected')(15,23) 15 | PsiElement(IND_STRING_CLOSE)('''')(23,25) 16 | PsiWhiteSpace('\n')(25,26) 17 | PsiElement(])(']')(26,27) 18 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/StringWithAntiquotation.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | STRING_OPEN ('"') 4 | STR ('a') 5 | $ ('$') 6 | { ('{') 7 | STRING_OPEN ('"') 8 | STR ('b') 9 | STRING_CLOSE ('"') 10 | } ('}') 11 | STR ('c') 12 | STRING_CLOSE ('"') 13 | WHITE_SPACE ('\n') 14 | IND_STRING_OPEN ('''') 15 | IND_STR ('a') 16 | $ ('$') 17 | { ('{') 18 | IND_STRING_OPEN ('''') 19 | IND_STR ('b') 20 | IND_STRING_CLOSE ('''') 21 | } ('}') 22 | IND_STR ('c') 23 | IND_STRING_CLOSE ('''') 24 | WHITE_SPACE ('\n') 25 | ] (']') 26 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/StringWithAntiquotation.nix: -------------------------------------------------------------------------------- 1 | [ 2 | "a${"b"}c" 3 | ''a${''b''}c'' 4 | ] 5 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/StringWithAntiquotation.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,29) 2 | NixExprListImpl(EXPR_LIST)(0,29) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace('\n')(1,2) 5 | NixStdStringImpl(STD_STRING)(2,12) 6 | PsiElement(STRING_OPEN)('"')(2,3) 7 | NixStringTextImpl(STRING_TEXT)(3,4) 8 | PsiElement(STR)('a')(3,4) 9 | NixAntiquotationImpl(ANTIQUOTATION)(4,10) 10 | PsiElement($)('$')(4,5) 11 | PsiElement({)('{')(5,6) 12 | NixStdStringImpl(STD_STRING)(6,9) 13 | PsiElement(STRING_OPEN)('"')(6,7) 14 | NixStringTextImpl(STRING_TEXT)(7,8) 15 | PsiElement(STR)('b')(7,8) 16 | PsiElement(STRING_CLOSE)('"')(8,9) 17 | PsiElement(})('}')(9,10) 18 | NixStringTextImpl(STRING_TEXT)(10,11) 19 | PsiElement(STR)('c')(10,11) 20 | PsiElement(STRING_CLOSE)('"')(11,12) 21 | PsiWhiteSpace('\n')(12,13) 22 | NixIndStringImpl(IND_STRING)(13,27) 23 | PsiElement(IND_STRING_OPEN)('''')(13,15) 24 | NixStringTextImpl(STRING_TEXT)(15,16) 25 | PsiElement(IND_STR)('a')(15,16) 26 | NixAntiquotationImpl(ANTIQUOTATION)(16,24) 27 | PsiElement($)('$')(16,17) 28 | PsiElement({)('{')(17,18) 29 | NixIndStringImpl(IND_STRING)(18,23) 30 | PsiElement(IND_STRING_OPEN)('''')(18,20) 31 | NixStringTextImpl(STRING_TEXT)(20,21) 32 | PsiElement(IND_STR)('b')(20,21) 33 | PsiElement(IND_STRING_CLOSE)('''')(21,23) 34 | PsiElement(})('}')(23,24) 35 | NixStringTextImpl(STRING_TEXT)(24,25) 36 | PsiElement(IND_STR)('c')(24,25) 37 | PsiElement(IND_STRING_CLOSE)('''')(25,27) 38 | PsiWhiteSpace('\n')(27,28) 39 | PsiElement(])(']')(28,29) 40 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/StringWithEscapeSequences.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | IND_STRING_OPEN ('''') 4 | IND_STR_ESCAPE (''''') 5 | IND_STRING_CLOSE ('''') 6 | WHITE_SPACE ('\n') 7 | STRING_OPEN ('"') 8 | STR ('a') 9 | STR_ESCAPE ('\$') 10 | STR ('{b}c') 11 | STRING_CLOSE ('"') 12 | WHITE_SPACE ('\n') 13 | IND_STRING_OPEN ('''') 14 | IND_STR ('a') 15 | IND_STR_ESCAPE ('''$') 16 | IND_STR ('{b}c') 17 | IND_STRING_CLOSE ('''') 18 | WHITE_SPACE ('\n') 19 | STRING_OPEN ('"') 20 | STR ('a') 21 | STR_ESCAPE ('\n') 22 | STR_ESCAPE ('\r') 23 | STR_ESCAPE ('\t') 24 | STR ('c') 25 | STRING_CLOSE ('"') 26 | WHITE_SPACE ('\n') 27 | IND_STRING_OPEN ('''') 28 | IND_STR ('a') 29 | IND_STR_ESCAPE ('''\n') 30 | IND_STR_ESCAPE ('''\r') 31 | IND_STR_ESCAPE ('''\t') 32 | IND_STR ('c') 33 | IND_STRING_CLOSE ('''') 34 | WHITE_SPACE ('\n') 35 | STRING_OPEN ('"') 36 | STR ('a') 37 | STR_ESCAPE ('\b') 38 | STR ('c') 39 | STRING_CLOSE ('"') 40 | WHITE_SPACE ('\n') 41 | IND_STRING_OPEN ('''') 42 | IND_STR ('a') 43 | IND_STR_ESCAPE ('''\b') 44 | IND_STR ('c') 45 | IND_STRING_CLOSE ('''') 46 | WHITE_SPACE ('\n') 47 | STRING_OPEN ('"') 48 | STR ('a') 49 | STR ('$$') 50 | STR ('{b}c') 51 | STRING_CLOSE ('"') 52 | WHITE_SPACE ('\n') 53 | IND_STRING_OPEN ('''') 54 | IND_STR ('a') 55 | IND_STR ('$$') 56 | IND_STR ('{b}c') 57 | IND_STRING_CLOSE ('''') 58 | WHITE_SPACE ('\n') 59 | ] (']') 60 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/StringWithEscapeSequences.nix: -------------------------------------------------------------------------------- 1 | [ 2 | ''''''' 3 | "a\${b}c" 4 | ''a''${b}c'' 5 | "a\n\r\tc" 6 | ''a''\n''\r''\tc'' 7 | "a\bc" 8 | ''a''\bc'' 9 | "a$${b}c" 10 | ''a$${b}c'' 11 | ] 12 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/StringWithEscapeSequences.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,104) 2 | NixExprListImpl(EXPR_LIST)(0,104) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace('\n')(1,2) 5 | NixIndStringImpl(IND_STRING)(2,9) 6 | PsiElement(IND_STRING_OPEN)('''')(2,4) 7 | NixStringTextImpl(STRING_TEXT)(4,7) 8 | PsiElement(IND_STR_ESCAPE)(''''')(4,7) 9 | PsiElement(IND_STRING_CLOSE)('''')(7,9) 10 | PsiWhiteSpace('\n')(9,10) 11 | NixStdStringImpl(STD_STRING)(10,19) 12 | PsiElement(STRING_OPEN)('"')(10,11) 13 | NixStringTextImpl(STRING_TEXT)(11,18) 14 | PsiElement(STR)('a')(11,12) 15 | PsiElement(STR_ESCAPE)('\$')(12,14) 16 | PsiElement(STR)('{b}c')(14,18) 17 | PsiElement(STRING_CLOSE)('"')(18,19) 18 | PsiWhiteSpace('\n')(19,20) 19 | NixIndStringImpl(IND_STRING)(20,32) 20 | PsiElement(IND_STRING_OPEN)('''')(20,22) 21 | NixStringTextImpl(STRING_TEXT)(22,30) 22 | PsiElement(IND_STR)('a')(22,23) 23 | PsiElement(IND_STR_ESCAPE)('''$')(23,26) 24 | PsiElement(IND_STR)('{b}c')(26,30) 25 | PsiElement(IND_STRING_CLOSE)('''')(30,32) 26 | PsiWhiteSpace('\n')(32,33) 27 | NixStdStringImpl(STD_STRING)(33,43) 28 | PsiElement(STRING_OPEN)('"')(33,34) 29 | NixStringTextImpl(STRING_TEXT)(34,42) 30 | PsiElement(STR)('a')(34,35) 31 | PsiElement(STR_ESCAPE)('\n')(35,37) 32 | PsiElement(STR_ESCAPE)('\r')(37,39) 33 | PsiElement(STR_ESCAPE)('\t')(39,41) 34 | PsiElement(STR)('c')(41,42) 35 | PsiElement(STRING_CLOSE)('"')(42,43) 36 | PsiWhiteSpace('\n')(43,44) 37 | NixIndStringImpl(IND_STRING)(44,62) 38 | PsiElement(IND_STRING_OPEN)('''')(44,46) 39 | NixStringTextImpl(STRING_TEXT)(46,60) 40 | PsiElement(IND_STR)('a')(46,47) 41 | PsiElement(IND_STR_ESCAPE)('''\n')(47,51) 42 | PsiElement(IND_STR_ESCAPE)('''\r')(51,55) 43 | PsiElement(IND_STR_ESCAPE)('''\t')(55,59) 44 | PsiElement(IND_STR)('c')(59,60) 45 | PsiElement(IND_STRING_CLOSE)('''')(60,62) 46 | PsiWhiteSpace('\n')(62,63) 47 | NixStdStringImpl(STD_STRING)(63,69) 48 | PsiElement(STRING_OPEN)('"')(63,64) 49 | NixStringTextImpl(STRING_TEXT)(64,68) 50 | PsiElement(STR)('a')(64,65) 51 | PsiElement(STR_ESCAPE)('\b')(65,67) 52 | PsiElement(STR)('c')(67,68) 53 | PsiElement(STRING_CLOSE)('"')(68,69) 54 | PsiWhiteSpace('\n')(69,70) 55 | NixIndStringImpl(IND_STRING)(70,80) 56 | PsiElement(IND_STRING_OPEN)('''')(70,72) 57 | NixStringTextImpl(STRING_TEXT)(72,78) 58 | PsiElement(IND_STR)('a')(72,73) 59 | PsiElement(IND_STR_ESCAPE)('''\b')(73,77) 60 | PsiElement(IND_STR)('c')(77,78) 61 | PsiElement(IND_STRING_CLOSE)('''')(78,80) 62 | PsiWhiteSpace('\n')(80,81) 63 | NixStdStringImpl(STD_STRING)(81,90) 64 | PsiElement(STRING_OPEN)('"')(81,82) 65 | NixStringTextImpl(STRING_TEXT)(82,89) 66 | PsiElement(STR)('a')(82,83) 67 | PsiElement(STR)('$$')(83,85) 68 | PsiElement(STR)('{b}c')(85,89) 69 | PsiElement(STRING_CLOSE)('"')(89,90) 70 | PsiWhiteSpace('\n')(90,91) 71 | NixIndStringImpl(IND_STRING)(91,102) 72 | PsiElement(IND_STRING_OPEN)('''')(91,93) 73 | NixStringTextImpl(STRING_TEXT)(93,100) 74 | PsiElement(IND_STR)('a')(93,94) 75 | PsiElement(IND_STR)('$$')(94,96) 76 | PsiElement(IND_STR)('{b}c')(96,100) 77 | PsiElement(IND_STRING_CLOSE)('''')(100,102) 78 | PsiWhiteSpace('\n')(102,103) 79 | PsiElement(])(']')(103,104) 80 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/StringWithMultipleLines.lexer.txt: -------------------------------------------------------------------------------- 1 | [ ('[') 2 | WHITE_SPACE ('\n') 3 | STRING_OPEN ('"') 4 | STR ('\n first\n second\n third\n') 5 | STRING_CLOSE ('"') 6 | WHITE_SPACE ('\n') 7 | IND_STRING_OPEN ('''') 8 | IND_STR ('\n first\n second\n third\n') 9 | IND_STRING_CLOSE ('''') 10 | WHITE_SPACE ('\n') 11 | ] (']') 12 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/StringWithMultipleLines.nix: -------------------------------------------------------------------------------- 1 | [ 2 | " 3 | first 4 | second 5 | third 6 | " 7 | '' 8 | first 9 | second 10 | third 11 | '' 12 | ] 13 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/StringWithMultipleLines.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,63) 2 | NixExprListImpl(EXPR_LIST)(0,63) 3 | PsiElement([)('[')(0,1) 4 | PsiWhiteSpace('\n')(1,2) 5 | NixStdStringImpl(STD_STRING)(2,30) 6 | PsiElement(STRING_OPEN)('"')(2,3) 7 | NixStringTextImpl(STRING_TEXT)(3,29) 8 | PsiElement(STR)('\n first\n second\n third\n')(3,29) 9 | PsiElement(STRING_CLOSE)('"')(29,30) 10 | PsiWhiteSpace('\n')(30,31) 11 | NixIndStringImpl(IND_STRING)(31,61) 12 | PsiElement(IND_STRING_OPEN)('''')(31,33) 13 | NixStringTextImpl(STRING_TEXT)(33,59) 14 | PsiElement(IND_STR)('\n first\n second\n third\n')(33,59) 15 | PsiElement(IND_STRING_CLOSE)('''')(59,61) 16 | PsiWhiteSpace('\n')(61,62) 17 | PsiElement(])(']')(62,63) 18 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Uri.lexer.txt: -------------------------------------------------------------------------------- 1 | URI ('http://example.org/foo.tar.bz2') 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Uri.nix: -------------------------------------------------------------------------------- 1 | http://example.org/foo.tar.bz2 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/Uri.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,30) 2 | NixExprUriImpl(EXPR_URI)(0,30) 3 | PsiElement(URI)('http://example.org/foo.tar.bz2')(0,30) 4 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/With.lexer.txt: -------------------------------------------------------------------------------- 1 | ⁠with ('with') 2 | WHITE_SPACE (' ') 3 | ID ('e1') 4 | ; (';') 5 | WHITE_SPACE (' ') 6 | ID ('e2') 7 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/With.nix: -------------------------------------------------------------------------------- 1 | with e1; e2 2 | -------------------------------------------------------------------------------- /src/test/testData/ParsingTest/With.txt: -------------------------------------------------------------------------------- 1 | Nix File(0,11) 2 | NixExprWithImpl(EXPR_WITH)(0,11) 3 | PsiElement(⁠with)('with')(0,4) 4 | PsiWhiteSpace(' ')(4,5) 5 | NixExprVarImpl(EXPR_VAR)(5,7) 6 | PsiElement(ID)('e1')(5,7) 7 | PsiElement(;)(';')(7,8) 8 | PsiWhiteSpace(' ')(8,9) 9 | NixExprVarImpl(EXPR_VAR)(9,11) 10 | PsiElement(ID)('e2')(9,11) 11 | --------------------------------------------------------------------------------