├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── .idea ├── artifacts │ ├── clojure_kit_jar.xml │ └── clojure_kit_zip.xml ├── codeStyleSettings.xml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── copyright │ ├── clojure_kit.xml │ └── profiles_settings.xml ├── encodings.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── jarRepositories.xml ├── kotlinc.xml ├── libraries │ ├── Clojure.xml │ ├── ClojureScript.xml │ └── WellKnownClojureLibs.xml ├── misc.xml ├── modules.xml ├── runConfigurations │ └── All_Tests.xml └── vcs.xml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── build.gradle.kts ├── clojure-kit.iml ├── gen └── org │ └── intellij │ └── clojure │ ├── parser │ ├── ClojureParser.java │ └── _ClojureLexer.java │ └── psi │ ├── CAccess.java │ ├── CCommented.java │ ├── CConstructor.java │ ├── CForm.java │ ├── CFun.java │ ├── CKeyword.java │ ├── CLVForm.java │ ├── CList.java │ ├── CLiteral.java │ ├── CMap.java │ ├── CMetadata.java │ ├── CPForm.java │ ├── CReaderMacro.java │ ├── CRegexp.java │ ├── CSForm.java │ ├── CSet.java │ ├── CSymbol.java │ ├── CVec.java │ ├── ClojureTypes.java │ ├── ClojureVisitor.java │ └── impl │ ├── CAccessImpl.java │ ├── CCommentedImpl.java │ ├── CConstructorImpl.java │ ├── CFormImpl.java │ ├── CFunImpl.java │ ├── CKeywordImpl.java │ ├── CLVFormImpl.java │ ├── CListImpl.java │ ├── CLiteralImpl.java │ ├── CMapImpl.java │ ├── CMetadataImpl.java │ ├── CPFormImpl.java │ ├── CReaderMacroImpl.java │ ├── CRegexpImpl.java │ ├── CSFormImpl.java │ ├── CSetImpl.java │ ├── CSymbolImpl.java │ └── CVecImpl.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── grammars ├── _ClojureLexer.flex └── clojure.bnf ├── resources ├── META-INF │ ├── MANIFEST.MF │ ├── plugin-copyright.xml │ ├── plugin-java.xml │ └── plugin.xml ├── colorSchemes │ ├── ClojureDarcula.xml │ └── ClojureDefault.xml ├── icons │ ├── clojure.svg │ ├── clojureFile.svg │ ├── namespace.svg │ └── symbol.svg ├── inspectionDescriptions │ └── ClojureResolveInspection.html ├── liveTemplates │ └── clojureLiveTemplates.xml └── messages │ └── ClojureBundle.properties ├── settings.gradle ├── src ├── actions │ └── structural-editing.kt ├── clojure-constants.kt ├── lang │ ├── clojure-colors.kt │ ├── clojure-editor-psi.kt │ ├── clojure-editor.kt │ ├── clojure-formatter.kt │ ├── clojure-inspections.kt │ ├── clojure-language.kt │ ├── clojure-parser.kt │ ├── clojure-psi-api.kt │ ├── clojure-psi-fileimpl.kt │ ├── clojure-psi-fragment.kt │ ├── clojure-psi-genimpl.kt │ ├── clojure-psi-index.kt │ ├── clojure-psi-java.kt │ ├── clojure-psi-resolve.kt │ ├── clojure-psi-stubs.kt │ ├── clojure-psi-symbols.kt │ ├── clojure-slices.kt │ └── clojure-usages.kt ├── org │ └── intellij │ │ └── clojure │ │ └── ui │ │ └── forms │ │ ├── CodeStyleOtherTab.form │ │ └── CodeStyleOtherTab.java ├── tools │ ├── debugger-jvm.kt │ ├── debugger.kt │ ├── nrepl-client.kt │ ├── tools-deps.kt │ ├── tools-repl.kt │ └── tools.kt ├── ui │ └── clojure-formatter-ui.kt └── util │ └── clojure-util.kt ├── testData ├── formatter │ ├── CodeSample.clj │ ├── FormatterFixes.clj │ ├── Simple.clj │ └── StyleGuide.clj ├── highlighting │ ├── ClojureFixes.clj │ ├── ClojureLang.txt │ ├── ClojureScript.txt │ └── samples.clj ├── lexer │ ├── DispatchAndQuote.txt │ ├── HighlightForm.txt │ ├── HighlightSingleSharp.txt │ ├── Literals.txt │ └── SymbolsAndKeywords.txt └── parser │ ├── CommentedForms.txt │ ├── FirstAndSimple.txt │ ├── InterOp.txt │ ├── MapPrefix.txt │ ├── SimpleFixes.txt │ ├── SimpleRecover.txt │ └── SimpleRecover2.txt └── tests └── lang ├── completion-tests.kt ├── editing-tests.kt ├── formatter-tests.kt ├── highlighting-tests.kt ├── language-tests.kt ├── refactoring-tests.kt ├── test-util.kt └── usages-tests.kt /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Dependabot configuration: 2 | # https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | # Maintain dependencies for Gradle dependencies 7 | - package-ecosystem: "gradle" 8 | directory: "/" 9 | target-branch: "next" 10 | schedule: 11 | interval: "daily" 12 | # Maintain dependencies for GitHub Actions 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | target-branch: "next" 16 | schedule: 17 | interval: "daily" 18 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow created for testing and preparing the plugin release in following steps: 2 | # - validate Gradle Wrapper, 3 | # - run 'test' and 'verifyPlugin' tasks, 4 | # - run Qodana inspections, 5 | # - run 'buildPlugin' task and prepare artifact for the further tests, 6 | # - run 'runPluginVerifier' task, 7 | # - create a draft release. 8 | # 9 | # Workflow is triggered on push and pull_request events. 10 | # 11 | # GitHub Actions reference: https://help.github.com/en/actions 12 | # 13 | ## JBIJPPTPL 14 | 15 | name: Build 16 | on: 17 | # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g. for dependabot pull requests) 18 | push: 19 | branches: [main] 20 | # Trigger the workflow on any pull request 21 | pull_request: 22 | 23 | jobs: 24 | 25 | # Run Gradle Wrapper Validation Action to verify the wrapper's checksum 26 | # Run verifyPlugin, IntelliJ Plugin Verifier, and test Gradle tasks 27 | # Build plugin and provide the artifact for the next workflow jobs 28 | build: 29 | name: Build 30 | runs-on: ubuntu-latest 31 | outputs: 32 | version: ${{ steps.properties.outputs.version }} 33 | changelog: ${{ steps.properties.outputs.changelog }} 34 | steps: 35 | 36 | # Check out current repository 37 | - name: Fetch Sources 38 | uses: actions/checkout@v2.4.0 39 | 40 | # Validate wrapper 41 | - name: Gradle Wrapper Validation 42 | uses: gradle/wrapper-validation-action@v1.0.4 43 | 44 | # Setup Java 11 environment for the next steps 45 | - name: Setup Java 46 | uses: actions/setup-java@v2 47 | with: 48 | distribution: zulu 49 | java-version: 11 50 | cache: gradle 51 | 52 | # Set environment variables 53 | - name: Export Properties 54 | id: properties 55 | shell: bash 56 | run: | 57 | PROPERTIES="$(./gradlew properties --console=plain -q)" 58 | VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')" 59 | NAME="$(echo "$PROPERTIES" | grep "^pluginName:" | cut -f2- -d ' ')" 60 | CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)" 61 | CHANGELOG="${CHANGELOG//'%'/'%25'}" 62 | CHANGELOG="${CHANGELOG//$'\n'/'%0A'}" 63 | CHANGELOG="${CHANGELOG//$'\r'/'%0D'}" 64 | 65 | echo "::set-output name=version::$VERSION" 66 | echo "::set-output name=name::$NAME" 67 | echo "::set-output name=changelog::$CHANGELOG" 68 | echo "::set-output name=pluginVerifierHomeDir::~/.pluginVerifier" 69 | 70 | ./gradlew listProductsReleases # prepare list of IDEs for Plugin Verifier 71 | 72 | # Run tests 73 | - name: Run Tests 74 | run: ./gradlew test 75 | 76 | # Collect Tests Result of failed tests 77 | - name: Collect Tests Result 78 | if: ${{ failure() }} 79 | uses: actions/upload-artifact@v2 80 | with: 81 | name: tests-result 82 | path: ${{ github.workspace }}/build/reports/tests 83 | 84 | # Cache Plugin Verifier IDEs 85 | - name: Setup Plugin Verifier IDEs Cache 86 | uses: actions/cache@v2.1.6 87 | with: 88 | path: ${{ steps.properties.outputs.pluginVerifierHomeDir }}/ides 89 | key: plugin-verifier-${{ hashFiles('build/listProductsReleases.txt') }} 90 | 91 | # Run Verify Plugin task and IntelliJ Plugin Verifier tool 92 | - name: Run Plugin Verification tasks 93 | run: ./gradlew runPluginVerifier -Pplugin.verifier.home.dir=${{ steps.properties.outputs.pluginVerifierHomeDir }} 94 | 95 | # Collect Plugin Verifier Result 96 | - name: Collect Plugin Verifier Result 97 | if: ${{ always() }} 98 | uses: actions/upload-artifact@v2 99 | with: 100 | name: pluginVerifier-result 101 | path: ${{ github.workspace }}/build/reports/pluginVerifier 102 | 103 | # Run Qodana inspections 104 | - name: Qodana - Code Inspection 105 | uses: JetBrains/qodana-action@v2.1-eap 106 | 107 | # Collect Qodana Result 108 | - name: Collect Qodana Result 109 | uses: actions/upload-artifact@v2 110 | with: 111 | name: qodana-result 112 | path: ${{ github.workspace }}/qodana 113 | 114 | # Prepare plugin archive content for creating artifact 115 | - name: Prepare Plugin Artifact 116 | id: artifact 117 | shell: bash 118 | run: | 119 | cd ${{ github.workspace }}/build/distributions 120 | FILENAME=`ls *.zip` 121 | unzip "$FILENAME" -d content 122 | 123 | echo "::set-output name=filename::$FILENAME" 124 | 125 | # Store already-built plugin as an artifact for downloading 126 | - name: Upload artifact 127 | uses: actions/upload-artifact@v2.2.4 128 | with: 129 | name: ${{ steps.artifact.outputs.filename }} 130 | path: ./build/distributions/content/*/* 131 | 132 | # Prepare a draft release for GitHub Releases page for the manual verification 133 | # If accepted and published, release workflow would be triggered 134 | releaseDraft: 135 | name: Release Draft 136 | if: github.event_name != 'pull_request' 137 | needs: build 138 | runs-on: ubuntu-latest 139 | steps: 140 | 141 | # Check out current repository 142 | - name: Fetch Sources 143 | uses: actions/checkout@v2.4.0 144 | 145 | # Remove old release drafts by using the curl request for the available releases with draft flag 146 | - name: Remove Old Release Drafts 147 | env: 148 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 149 | run: | 150 | gh api repos/{owner}/{repo}/releases \ 151 | --jq '.[] | select(.draft == true) | .id' \ 152 | | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{} 153 | 154 | # Create new release draft - which is not publicly visible and requires manual acceptance 155 | - name: Create Release Draft 156 | env: 157 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 158 | run: | 159 | gh release create v${{ needs.build.outputs.version }} \ 160 | --draft \ 161 | --title "v${{ needs.build.outputs.version }}" \ 162 | --notes "$(cat << 'EOM' 163 | ${{ needs.build.outputs.changelog }} 164 | EOM 165 | )" 166 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow created for handling the release process based on the draft release prepared 2 | # with the Build workflow. Running the publishPlugin task requires the PUBLISH_TOKEN secret provided. 3 | 4 | name: Release 5 | on: 6 | release: 7 | types: [prereleased, released] 8 | 9 | jobs: 10 | 11 | # Prepare and publish the plugin to the Marketplace repository 12 | release: 13 | name: Publish Plugin 14 | runs-on: ubuntu-latest 15 | steps: 16 | 17 | # Check out current repository 18 | - name: Fetch Sources 19 | uses: actions/checkout@v2.3.5 20 | with: 21 | ref: ${{ github.event.release.tag_name }} 22 | 23 | # Setup Java 11 environment for the next steps 24 | - name: Setup Java 25 | uses: actions/setup-java@v2 26 | with: 27 | distribution: zulu 28 | java-version: 11 29 | cache: gradle 30 | 31 | # Set environment variables 32 | - name: Export Properties 33 | id: properties 34 | shell: bash 35 | run: | 36 | CHANGELOG="$(cat << 'EOM' | sed -e 's/^[[:space:]]*$//g' -e '/./,$!d' 37 | ${{ github.event.release.body }} 38 | EOM 39 | )" 40 | 41 | echo "::set-output name=changelog::$CHANGELOG" 42 | 43 | # Update Unreleased section with the current release note 44 | - name: Patch Changelog 45 | if: ${{ steps.properties.outputs.changelog != '' }} 46 | run: | 47 | ./gradlew patchChangelog --release-note "$(cat << 'EOM' 48 | ${{ steps.properties.outputs.changelog }} 49 | EOM 50 | )" 51 | 52 | # Publish JAR to Maven Central 53 | - name: Publish library 54 | env: 55 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} 56 | MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} 57 | MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 58 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }} 59 | SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} 60 | run: ./gradlew publish \ 61 | -PmavenCentralUsername=$MAVEN_CENTRAL_USERNAME \ 62 | -PmavenCentralPassword=$MAVEN_CENTRAL_PASSWORD \ 63 | -PsigningKey=$SIGNING_KEY \ 64 | -PsigningPassword=$SIGNING_PASSWORD 65 | 66 | # Publish the plugin to the Marketplace 67 | - name: Publish Plugin 68 | env: 69 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} 70 | run: ./gradlew publishPlugin 71 | 72 | # Upload artifact as a release asset 73 | - name: Upload Release Asset 74 | env: 75 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 76 | run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/* 77 | 78 | # Create pull request 79 | - name: Create Pull Request 80 | if: ${{ steps.properties.outputs.changelog != '' }} 81 | env: 82 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 83 | run: | 84 | VERSION="${{ github.event.release.tag_name }}" 85 | BRANCH="changelog-update-$VERSION" 86 | 87 | git config user.email "action@github.com" 88 | git config user.name "GitHub Action" 89 | 90 | git checkout -b $BRANCH 91 | git commit -am "Changelog update - $VERSION" 92 | git push --set-upstream origin $BRANCH 93 | 94 | gh pr create \ 95 | --title "Changelog update - \`$VERSION\`" \ 96 | --body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \ 97 | --base main \ 98 | --head $BRANCH 99 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/workspace.xml 3 | .idea/dictionaries/ 4 | .idea/shelf/ 5 | out/ 6 | binaries/ 7 | build/ 8 | target/ 9 | classes/ 10 | checkouts/ 11 | .gradle/ 12 | pom.xml* 13 | .lein-* 14 | .nrepl-port 15 | -------------------------------------------------------------------------------- /.idea/artifacts/clojure_kit_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/binaries 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/artifacts/clojure_kit_zip.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/binaries 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 156 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /.idea/copyright/clojure_kit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/libraries/Clojure.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/libraries/ClojureScript.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /.idea/libraries/WellKnownClojureLibs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/runConfigurations/All_Tests.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Clojure-Kit Changelog 2 | 3 | ## Unreleased 4 | 5 | * CI: Integration with [gradle-changelog-plugin](https://github.com/JetBrains/gradle-changelog-plugin) 6 | * CI: GitHub Actions Workflow based on [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template) 7 | * CI: Dependabot integration 8 | 9 | ## 2020.3.1 10 | 11 | * platform: minor compatibility fixes 12 | 13 | ## 2020.3 14 | 15 | * parser: allow no space between some tokens 16 | * resolve: namespaces without ":as" (#35) 17 | * resolve: check correct quotes in definitions 18 | * resolve: improve namespaces handling 19 | * editor: highlight missing namespaces 20 | * platform: IntelliJ IDEA 2020.3 21 | 22 | ## 2020.1 23 | 24 | * formatter: missing newline after a line comment (#31) 25 | * resolve: nested vectors in `require` (#33) 26 | * platform: IntelliJ IDEA 2020.1 27 | 28 | ## 2019.3.1 29 | 30 | * editor: make "smart kill" and "smart parens" configurable (Smart Keys | Clojure) 31 | * editor: turn "smart kill" and "smart parens" off by default 32 | * deps: fix dependencies cache file being a directory 33 | * java: fix resolve on Java 11 34 | * platform: IntelliJ IDEA 2019.3 35 | 36 | ## 2019.3 37 | 38 | * platform: IntelliJ IDEA 2019.3 EAP 39 | 40 | ## 0.7.6 41 | 42 | * resolve: fix qualified :keys destructuring 43 | * resolve: support this in (reify), (proxy) and (extend) 44 | * resolve: support (..), (->) and (doto) w/ and w/o parens 45 | * resolve: skip not quoted lists in ns elements 46 | * deps: notify if tool process failed to start 47 | * debugger: handle munged names in evaluator 48 | * debugger: workaround missing autoboxing for primitives eval 49 | * resolve: force JVM name for inner classes; fix (.method class) 50 | * resolve: better dynamic condition in . and .. 51 | * resolve: avoid resetting RESOLVE_SKIPPED in parallel 52 | * rename: fix extra space on rename (sym.) 53 | * rename: handle ::keys destructuring bindings 54 | * resolve: fix alias and some.alias confusion 55 | * resolve: clarify (.call obj) vs (call obj) in various cases 56 | * resolve: support mixed PSI/ASM class hierarchies 57 | * lexer: fix BigInteger numbers and octal chars literals 58 | * lexer: improve bad literals handling 59 | * resolve: improve qualified tags handling 60 | * tools: update nREPL dependencies #30 61 | 62 | ## 0.7.5 63 | 64 | * Editor: semantic highlighting (rainbow symbols) 65 | * Resolve: resolve java methods from super-interfaces 66 | * Resolve: resolve defrecord, deftype methods and fields 67 | * Usages: search for keywords and namespaces in whole project 68 | * Dependencies: support *.edn files 69 | * Dependencies: show in Project | External Libraries 70 | * Parser: fix #_, (a.b/c.) and \uNNNN parsing 71 | * REPL: fix execution from editor 72 | * UI: new SVG icons 73 | 74 | ## 0.7.4 75 | 76 | * Debugger: initial java debugger integration 77 | * QuickDoc: fix specs and show macroexpand from repl 78 | * QuickDoc: show info for syntax tokens, e.g. ~@, #^, etc. 79 | * Editor: Context Info and Move Left/Right actions 80 | * Editor: data-reader & name declaration colors 81 | * Editor: support custom folding regions 82 | * Clojure: better support for #_ forms 83 | 84 | ## 0.7.3 85 | 86 | * REPL: stdin/stdout/stderr support 87 | * REPL: use file ns when evaluating from a file 88 | * Editor: Copy Reference action 89 | * Editor: splice at caret position 90 | * Editor: error recovery in case of extra closing paren 91 | 92 | ## 0.7.2 93 | 94 | * IntelliJ Platform 2018.1 API compatibility 95 | * Clojure 1.9.0 compatibility (##Inf, ##-Inf, ##NaN) 96 | 97 | ## 0.7.1 98 | 99 | * IntelliJ Platform 2017.2.5 and 2017.3 API compatibility 100 | * Misc: use the latest versions of Kotlin & Gradle 101 | 102 | ## 0.7.0 103 | 104 | * Editor: multi-method & protocol method navigation (`ctrl-U`, `ctrl-alt-B`) 105 | * Editor: parameter info inlays; expression type hint 106 | * Formatter: follow bbatsov style guide 107 | * Code style: ;; (double-semicolon) commenting toggle 108 | * QuickDoc: search and display related specs 109 | * REPL: the first repl gets exclusive mode by default 110 | * Internals: redesigned AST/PSI, name resolution, indices and etc. 111 | 112 | ## 0.5.0 113 | 114 | * REPL: connect to remote REPL 115 | * REPL: send all commands to one specific REPL 116 | * REPL: console history actions 117 | * Editor: complete namespaces and keywords 118 | * Structural editing: improved caret handling 119 | * Main menu: add clojure actions to Edit and Tools 120 | 121 | ## 0.4.4 122 | 123 | * Editor: improved structural editing actions 124 | * Editor: more items in structure view and breadcrumbs 125 | * Editor: some default colors for **Default** and **Darcula** color schemes 126 | * Editor: `(comment)`, `#_` and quoted-symbol literal coloring 127 | * ClojureScript: resolve and usage search for `::aliased/keywords` 128 | * REPL: detect running nrepl via `.nrepl-port` file 129 | 130 | ## 0.4.3 131 | 132 | * Language: basic language support for Clojure and ClojureScript 133 | * Editor: colors, completion, navigation, parameter info, quickdoc and live templates 134 | * Code Insight: `Analyze data flow [to | from] here` 135 | * Structural editing: `slurp`, `barf`, `splice`, `rise`, `kill` and smart `delete`, `backspace` 136 | * Dependencies: resolve `lein` and `boot` projects dependencies to `~/.m2/` repository 137 | * REPL: `lein` and `boot` supported 138 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2000-present Greg Shrago 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may 4 | obtain a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and 10 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Clojure-Kit 3 | ================== 4 | [![Build Status](https://teamcity.jetbrains.com/app/rest/builds/buildType:(id:IntellijIdeaPlugins_ClojureKit_Build)/statusIcon.svg?guest=1)](https://teamcity.jetbrains.com/viewType.html?buildTypeId=IntellijIdeaPlugins_ClojureKit_Build&guest=1) 5 | [![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0) 6 | 7 | Clojure and ClojureScript [plugin](https://plugins.jetbrains.com/plugin/8636) for IntelliJ-based tools. 8 | 9 | Quick links: [Latest dev build](https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:IntellijIdeaPlugins_ClojureKit_Build,status:SUCCESS/artifacts/content/ClojureKit*.zip), 10 | [Changelog](CHANGELOG.md). 11 | 12 | 13 | * Aims to be as zero configuration as possible 14 | * Adds color options, basic formatter, documentation, structure view and breadcrumbs 15 | * Provides `Analyze data flow [to | from] here` functionality 16 | * Features basic [Leiningen](https://github.com/technomancy/leiningen) and [Boot](https://github.com/boot-clj/boot) support 17 | * Plays nice with `IDE Scripting Console` 18 | * Written in [Kotlin](https://github.com/JetBrains/kotlin) with [Grammar-Kit](https://github.com/JetBrains/Grammar-Kit) 19 | 20 | FAQ 21 | ========== 22 | 23 | Q. How to install the plugin?
24 | A. Go to `Settings | Plugins`, press `Browse Repositories` button, search for `Clojure-Kit`, install, relaunch. 25 | 26 | Q. How to open my project?
27 | A. Use whichever way IDE provides to add a project directory to **Project View**. 28 | 29 | Q. Where are my dependencies?
30 | A. Dependencies are collected from `lein` or `boot` on project load. There's no dedicated UI to view or configure them. 31 | Use **Sync [All] Dependencies** actions for the corresponding `project.clj` or `build.boot` 32 | available in editor floating toolbar (upper-right corner), **Project View** and **Goto Action** popup (`ctrl-shift-A` or `cmd-shift-A`). 33 | 34 | Q. How to launch REPL?
35 | A. Use **Execute in REPL** action (`ctrl-enter` or `cmd-enter`) to send the selected text or a form under caret to REPL. 36 | Either a new or existing nREPL server console UI will show up. Then forms can be sent right from project files or the console editor. 37 | 38 | Q. How to connect to remote REPL or ClojureScript REPL on a different port?
39 | A. Use **Connect to REPL** action (`ctrl-shift-P` or `cmd-shift-P`) to enter host, port or nrepl URL and create a new remote console. 40 | Remote consoles are not mapped to project files, use **Exclusive Mode** toolbar toggle or popup (`ctrl-shift-L` or `cmd-shift-L`) 41 | to redirect all commands to one specific REPL. 42 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | fun properties(key: String) = project.findProperty(key)?.toString() 4 | 5 | plugins { 6 | id("org.jetbrains.intellij") version "1.2.1" 7 | id("org.jetbrains.changelog") version "1.3.1" 8 | id("idea") 9 | id("java") 10 | id("org.jetbrains.kotlin.jvm") version "1.4.10" 11 | } 12 | 13 | version = properties("pluginVersion").toString() 14 | 15 | repositories { 16 | mavenCentral() 17 | maven { url = uri("https://clojars.org/repo") } 18 | } 19 | 20 | dependencies { 21 | compileOnly("org.jetbrains:annotations:22.0.0") 22 | testRuntimeOnly("org.clojure:clojure:${properties("clojureVersion")}") 23 | testRuntimeOnly("org.clojure:clojurescript:${properties("cljsVersion")}") 24 | compileOnly(files("${System.getProperties()["java.home"]}/../lib/tools.jar")) 25 | } 26 | 27 | idea { 28 | module { 29 | generatedSourceDirs.add(file("gen")) 30 | } 31 | } 32 | 33 | intellij { 34 | pluginName.set(properties("pluginName")) 35 | version.set(properties("ideaVersion")) 36 | type.set("IC") 37 | plugins.set(listOf("copyright", "java")) 38 | updateSinceUntilBuild.set(false) 39 | } 40 | 41 | changelog { 42 | header.set("${{ -> version.get() }}") 43 | headerParserRegex.set("""(\d+(\.\d+)+)""") 44 | itemPrefix.set("*") 45 | unreleasedTerm.set("Unreleased") 46 | } 47 | 48 | val artifactsPath = properties("artifactsPath").toString() 49 | 50 | val buildClojureKitJar = tasks.create("buildClojureKitJar") { 51 | dependsOn("assemble") 52 | archiveBaseName.set("Clojure-kit") 53 | destinationDirectory.set(file(artifactsPath)) 54 | manifest { 55 | from("$rootDir/resources/META-INF/MANIFEST.MF") 56 | } 57 | from(sourceSets.main.get().output) 58 | } 59 | 60 | tasks { 61 | withType { 62 | sourceCompatibility = properties("javaVersion") 63 | targetCompatibility = properties("javaVersion") 64 | } 65 | 66 | withType { 67 | kotlinOptions { 68 | jvmTarget = properties("javaVersion")!! 69 | apiVersion = properties("kotlinApiVersion")!! 70 | } 71 | } 72 | 73 | withType { 74 | useJUnit() 75 | include("**/*Test.class") 76 | isScanForTestClasses = false 77 | ignoreFailures = true 78 | } 79 | 80 | withType().configureEach { 81 | (options as StandardJavadocDocletOptions).apply { 82 | addStringOption("Xdoclint:none", "-quiet") 83 | } 84 | } 85 | 86 | wrapper { 87 | gradleVersion = properties("gradleVersion") 88 | } 89 | 90 | sourceSets { 91 | main { 92 | java.srcDirs("src", "gen") 93 | resources.srcDirs("resources") 94 | } 95 | test { 96 | java.srcDirs("tests") 97 | } 98 | } 99 | 100 | buildSearchableOptions { 101 | enabled = false 102 | } 103 | 104 | patchPluginXml { 105 | sinceBuild.set(properties("pluginSinceIdeaBuild")) 106 | changeNotes.set(provider { 107 | changelog.run { 108 | getOrNull(project.version.toString()) ?: getLatest() 109 | }.toHTML() + "Full change log..." 110 | }) 111 | } 112 | 113 | val buildClojureKitZip = create("buildClojureKitZip") { 114 | dependsOn(buildClojureKitJar) 115 | archiveBaseName.set("ClojureKit") 116 | destinationDirectory.set(file(artifactsPath)) 117 | from(buildClojureKitJar.outputs) { 118 | into("/ClojureKit/lib") 119 | } 120 | } 121 | 122 | create("artifacts") { 123 | dependsOn(buildClojureKitJar, buildClojureKitZip) 124 | } 125 | 126 | defaultTasks("clean", "artifacts", "test") 127 | } -------------------------------------------------------------------------------- /clojure-kit.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CAccess.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CAccess extends CSForm { 9 | 10 | @NotNull 11 | CSymbol getSymbol(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CCommented.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CCommented extends CElement { 9 | 10 | @Nullable 11 | CForm getForm(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CConstructor.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CConstructor extends CPForm { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CForm.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CForm extends CElement { 9 | 10 | @NotNull 11 | List getMetas(); 12 | 13 | @NotNull 14 | List getReaderMacros(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CFun.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CFun extends CList { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CKeyword.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CKeyword extends CSForm { 9 | 10 | @NotNull 11 | CSymbol getSymbol(); 12 | 13 | @NotNull 14 | String getName(); 15 | 16 | @NotNull 17 | String getNamespace(); 18 | 19 | @NotNull 20 | String getQualifiedName(); 21 | 22 | int getTextOffset(); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CLVForm.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CLVForm extends CPForm { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CList.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CList extends CLVForm { 9 | 10 | int getTextOffset(); 11 | 12 | @Nullable 13 | CSymbol getFirst(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CLiteral.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.tree.IElementType; 8 | 9 | public interface CLiteral extends CSForm { 10 | 11 | @Nullable 12 | IElementType getLiteralType(); 13 | 14 | @NotNull 15 | String getLiteralText(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CMap.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CMap extends CPForm { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CMetadata.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CMetadata extends CElement { 9 | 10 | @Nullable 11 | CForm getForm(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CPForm.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CPForm extends CForm { 9 | 10 | @NotNull 11 | List getForms(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CReaderMacro.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CReaderMacro extends CElement { 9 | 10 | @Nullable 11 | CSymbol getSymbol(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CRegexp.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CRegexp extends CLiteral { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CSForm.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CSForm extends CForm { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CSet.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CSet extends CPForm { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CSymbol.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiQualifiedReference; 8 | 9 | public interface CSymbol extends CSForm { 10 | 11 | @NotNull 12 | String getName(); 13 | 14 | @NotNull 15 | String getQualifiedName(); 16 | 17 | @Nullable 18 | CSymbol getQualifier(); 19 | 20 | int getTextOffset(); 21 | 22 | @NotNull 23 | PsiQualifiedReference getReference(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/CVec.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.psi.PsiElement; 7 | 8 | public interface CVec extends CLVForm { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/ClojureTypes.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import com.intellij.psi.tree.IElementType; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.lang.ASTNode; 7 | import org.intellij.clojure.psi.impl.*; 8 | import com.intellij.psi.impl.source.tree.CompositePsiElement; 9 | 10 | public interface ClojureTypes { 11 | 12 | IElementType C_ACCESS = new ClojureNodeType("C_ACCESS"); 13 | IElementType C_COMMENTED = new ClojureNodeType("C_COMMENTED"); 14 | IElementType C_CONSTRUCTOR = new ClojureNodeType("C_CONSTRUCTOR"); 15 | IElementType C_FORM = new ClojureNodeType("C_FORM"); 16 | IElementType C_FUN = new ClojureNodeType("C_FUN"); 17 | IElementType C_KEYWORD = new ClojureNodeType("C_KEYWORD"); 18 | IElementType C_LIST = new ClojureNodeType("C_LIST"); 19 | IElementType C_LITERAL = new ClojureNodeType("C_LITERAL"); 20 | IElementType C_MAP = new ClojureNodeType("C_MAP"); 21 | IElementType C_METADATA = new ClojureNodeType("C_METADATA"); 22 | IElementType C_READER_MACRO = new ClojureNodeType("C_READER_MACRO"); 23 | IElementType C_REGEXP = new ClojureNodeType("C_REGEXP"); 24 | IElementType C_SET = new ClojureNodeType("C_SET"); 25 | IElementType C_SYMBOL = new ClojureNodeType("C_SYMBOL"); 26 | IElementType C_VEC = new ClojureNodeType("C_VEC"); 27 | 28 | IElementType C_AT = new ClojureTokenType("@"); 29 | IElementType C_BOOL = new ClojureTokenType("bool"); 30 | IElementType C_BRACE1 = new ClojureTokenType("{"); 31 | IElementType C_BRACE2 = new ClojureTokenType("}"); 32 | IElementType C_BRACKET1 = new ClojureTokenType("["); 33 | IElementType C_BRACKET2 = new ClojureTokenType("]"); 34 | IElementType C_CHAR = new ClojureTokenType("char"); 35 | IElementType C_COLON = new ClojureTokenType(":"); 36 | IElementType C_COLONCOLON = new ClojureTokenType("::"); 37 | IElementType C_COMMA = new ClojureTokenType(","); 38 | IElementType C_DOT = new ClojureTokenType("."); 39 | IElementType C_DOTDASH = new ClojureTokenType(".-"); 40 | IElementType C_HAT = new ClojureTokenType("^"); 41 | IElementType C_HEXNUM = new ClojureTokenType("hexnum"); 42 | IElementType C_NIL = new ClojureTokenType("nil"); 43 | IElementType C_NUMBER = new ClojureTokenType("number"); 44 | IElementType C_PAREN1 = new ClojureTokenType("("); 45 | IElementType C_PAREN2 = new ClojureTokenType(")"); 46 | IElementType C_QUOTE = new ClojureTokenType("'"); 47 | IElementType C_RATIO = new ClojureTokenType("ratio"); 48 | IElementType C_RDXNUM = new ClojureTokenType("rdxnum"); 49 | IElementType C_SHARP = new ClojureTokenType("#"); 50 | IElementType C_SHARP_COMMENT = new ClojureTokenType("#_"); 51 | IElementType C_SHARP_EQ = new ClojureTokenType("#="); 52 | IElementType C_SHARP_HAT = new ClojureTokenType("#^"); 53 | IElementType C_SHARP_NS = new ClojureTokenType("#:"); 54 | IElementType C_SHARP_QMARK = new ClojureTokenType("#?"); 55 | IElementType C_SHARP_QMARK_AT = new ClojureTokenType("#?@"); 56 | IElementType C_SHARP_QUOTE = new ClojureTokenType("#'"); 57 | IElementType C_SHARP_SYM = new ClojureTokenType("##"); 58 | IElementType C_SLASH = new ClojureTokenType("/"); 59 | IElementType C_STRING = new ClojureTokenType("string"); 60 | IElementType C_SYM = new ClojureTokenType("sym"); 61 | IElementType C_SYNTAX_QUOTE = new ClojureTokenType("`"); 62 | IElementType C_TILDE = new ClojureTokenType("~"); 63 | IElementType C_TILDE_AT = new ClojureTokenType("~@"); 64 | 65 | class Factory { 66 | public static CompositePsiElement createElement(IElementType type) { 67 | if (type == C_ACCESS) { 68 | return new CAccessImpl(type); 69 | } 70 | else if (type == C_COMMENTED) { 71 | return new CCommentedImpl(type); 72 | } 73 | else if (type == C_CONSTRUCTOR) { 74 | return new CConstructorImpl(type); 75 | } 76 | else if (type == C_FORM) { 77 | return new CFormImpl(type); 78 | } 79 | else if (type == C_FUN) { 80 | return new CFunImpl(type); 81 | } 82 | else if (type == C_KEYWORD) { 83 | return new CKeywordImpl(type); 84 | } 85 | else if (type == C_LIST) { 86 | return new CListImpl(type); 87 | } 88 | else if (type == C_LITERAL) { 89 | return new CLiteralImpl(type); 90 | } 91 | else if (type == C_MAP) { 92 | return new CMapImpl(type); 93 | } 94 | else if (type == C_METADATA) { 95 | return new CMetadataImpl(type); 96 | } 97 | else if (type == C_READER_MACRO) { 98 | return new CReaderMacroImpl(type); 99 | } 100 | else if (type == C_REGEXP) { 101 | return new CRegexpImpl(type); 102 | } 103 | else if (type == C_SET) { 104 | return new CSetImpl(type); 105 | } 106 | else if (type == C_SYMBOL) { 107 | return new CSymbolImpl(type); 108 | } 109 | else if (type == C_VEC) { 110 | return new CVecImpl(type); 111 | } 112 | throw new AssertionError("Unknown element type: " + type); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/ClojureVisitor.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi; 3 | 4 | import org.jetbrains.annotations.*; 5 | import com.intellij.psi.PsiElementVisitor; 6 | 7 | public class ClojureVisitor extends PsiElementVisitor { 8 | 9 | public void visitAccess(@NotNull CAccess o) { 10 | visitSForm(o); 11 | } 12 | 13 | public void visitCommented(@NotNull CCommented o) { 14 | visitElement(o); 15 | } 16 | 17 | public void visitConstructor(@NotNull CConstructor o) { 18 | visitPForm(o); 19 | } 20 | 21 | public void visitForm(@NotNull CForm o) { 22 | visitElement(o); 23 | } 24 | 25 | public void visitFun(@NotNull CFun o) { 26 | visitList(o); 27 | } 28 | 29 | public void visitKeyword(@NotNull CKeyword o) { 30 | visitSForm(o); 31 | } 32 | 33 | public void visitLVForm(@NotNull CLVForm o) { 34 | visitPForm(o); 35 | } 36 | 37 | public void visitList(@NotNull CList o) { 38 | visitLVForm(o); 39 | } 40 | 41 | public void visitLiteral(@NotNull CLiteral o) { 42 | visitSForm(o); 43 | } 44 | 45 | public void visitMap(@NotNull CMap o) { 46 | visitPForm(o); 47 | } 48 | 49 | public void visitMetadata(@NotNull CMetadata o) { 50 | visitElement(o); 51 | } 52 | 53 | public void visitPForm(@NotNull CPForm o) { 54 | visitForm(o); 55 | } 56 | 57 | public void visitReaderMacro(@NotNull CReaderMacro o) { 58 | visitElement(o); 59 | } 60 | 61 | public void visitRegexp(@NotNull CRegexp o) { 62 | visitLiteral(o); 63 | } 64 | 65 | public void visitSForm(@NotNull CSForm o) { 66 | visitForm(o); 67 | } 68 | 69 | public void visitSet(@NotNull CSet o) { 70 | visitPForm(o); 71 | } 72 | 73 | public void visitSymbol(@NotNull CSymbol o) { 74 | visitSForm(o); 75 | } 76 | 77 | public void visitVec(@NotNull CVec o) { 78 | visitLVForm(o); 79 | } 80 | 81 | public void visitElement(@NotNull CElement o) { 82 | super.visitElement(o); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CAccessImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CAccessImpl extends CSFormImpl implements CAccess { 15 | 16 | public CAccessImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitAccess(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | @Override 30 | @NotNull 31 | public CSymbol getSymbol() { 32 | return PsiTreeUtil.getChildOfType(this, CSymbol.class); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CCommentedImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CCommentedImpl extends CComposite implements CCommented { 15 | 16 | public CCommentedImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitCommented(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | @Override 30 | @Nullable 31 | public CForm getForm() { 32 | return PsiTreeUtil.getChildOfType(this, CForm.class); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CConstructorImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CConstructorImpl extends CPFormImpl implements CConstructor { 15 | 16 | public CConstructorImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitConstructor(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CFormImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CFormImpl extends CComposite implements CForm { 15 | 16 | public CFormImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitForm(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | @Override 30 | @NotNull 31 | public List getMetas() { 32 | return PsiTreeUtil.getChildrenOfTypeAsList(this, CMetadata.class); 33 | } 34 | 35 | @Override 36 | @NotNull 37 | public List getReaderMacros() { 38 | return PsiTreeUtil.getChildrenOfTypeAsList(this, CReaderMacro.class); 39 | } 40 | 41 | @Override 42 | @NotNull 43 | public String toString() { 44 | return ClojurePsiImplUtil.toString(this); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CFunImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CFunImpl extends CListImpl implements CFun { 15 | 16 | public CFunImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitFun(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CKeywordImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CKeywordImpl extends CKeywordBase implements CKeyword { 15 | 16 | public CKeywordImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitKeyword(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | @Override 30 | @NotNull 31 | public CSymbol getSymbol() { 32 | return PsiTreeUtil.getChildOfType(this, CSymbol.class); 33 | } 34 | 35 | @Override 36 | @NotNull 37 | public String getName() { 38 | return ClojurePsiImplUtil.getName(this); 39 | } 40 | 41 | @Override 42 | @NotNull 43 | public String getNamespace() { 44 | return ClojurePsiImplUtil.getNamespace(this); 45 | } 46 | 47 | @Override 48 | public int getTextOffset() { 49 | return ClojurePsiImplUtil.getTextOffset(this); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CLVFormImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CLVFormImpl extends CPFormImpl implements CLVForm { 15 | 16 | public CLVFormImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitLVForm(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CListImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CListImpl extends CListBase implements CList { 15 | 16 | public CListImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitList(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | @Override 30 | public int getTextOffset() { 31 | return ClojurePsiImplUtil.getTextOffset(this); 32 | } 33 | 34 | @Override 35 | @Nullable 36 | public CSymbol getFirst() { 37 | return ClojurePsiImplUtil.getFirst(this); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CLiteralImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CLiteralImpl extends CSFormImpl implements CLiteral { 15 | 16 | public CLiteralImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitLiteral(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | @Override 30 | @Nullable 31 | public IElementType getLiteralType() { 32 | return ClojurePsiImplUtil.getLiteralType(this); 33 | } 34 | 35 | @Override 36 | @NotNull 37 | public String getLiteralText() { 38 | return ClojurePsiImplUtil.getLiteralText(this); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CMapImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CMapImpl extends CPFormImpl implements CMap { 15 | 16 | public CMapImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitMap(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CMetadataImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CMetadataImpl extends CComposite implements CMetadata { 15 | 16 | public CMetadataImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitMetadata(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | @Override 30 | @Nullable 31 | public CForm getForm() { 32 | return PsiTreeUtil.getChildOfType(this, CForm.class); 33 | } 34 | 35 | @Override 36 | @NotNull 37 | public String toString() { 38 | return ClojurePsiImplUtil.toString(this); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CPFormImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CPFormImpl extends CFormImpl implements CPForm { 15 | 16 | public CPFormImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitPForm(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | @Override 30 | @NotNull 31 | public List getForms() { 32 | return PsiTreeUtil.getChildrenOfTypeAsList(this, CForm.class); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CReaderMacroImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CReaderMacroImpl extends CComposite implements CReaderMacro { 15 | 16 | public CReaderMacroImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitReaderMacro(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | @Override 30 | @Nullable 31 | public CSymbol getSymbol() { 32 | return PsiTreeUtil.getChildOfType(this, CSymbol.class); 33 | } 34 | 35 | @Override 36 | @NotNull 37 | public String toString() { 38 | return ClojurePsiImplUtil.toString(this); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CRegexpImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CRegexpImpl extends CLiteralImpl implements CRegexp { 15 | 16 | public CRegexpImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitRegexp(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CSFormImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CSFormImpl extends CFormImpl implements CSForm { 15 | 16 | public CSFormImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitSForm(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CSetImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CSetImpl extends CPFormImpl implements CSet { 15 | 16 | public CSetImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitSet(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CSymbolImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.PsiQualifiedReference; 13 | import com.intellij.psi.tree.IElementType; 14 | 15 | public class CSymbolImpl extends CSymbolBase implements CSymbol { 16 | 17 | public CSymbolImpl(@NotNull IElementType type) { 18 | super(type); 19 | } 20 | 21 | public void accept(@NotNull ClojureVisitor visitor) { 22 | visitor.visitSymbol(this); 23 | } 24 | 25 | public void accept(@NotNull PsiElementVisitor visitor) { 26 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 27 | else super.accept(visitor); 28 | } 29 | 30 | @Override 31 | @NotNull 32 | public String getName() { 33 | return ClojurePsiImplUtil.getName(this); 34 | } 35 | 36 | @Override 37 | @NotNull 38 | public String getQualifiedName() { 39 | return ClojurePsiImplUtil.getQualifiedName(this); 40 | } 41 | 42 | @Override 43 | @Nullable 44 | public CSymbol getQualifier() { 45 | return ClojurePsiImplUtil.getQualifier(this); 46 | } 47 | 48 | @Override 49 | public int getTextOffset() { 50 | return ClojurePsiImplUtil.getTextOffset(this); 51 | } 52 | 53 | @Override 54 | @NotNull 55 | public PsiQualifiedReference getReference() { 56 | return ClojurePsiImplUtil.getReference(this); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /gen/org/intellij/clojure/psi/impl/CVecImpl.java: -------------------------------------------------------------------------------- 1 | // This is a generated file. Not intended for manual editing. 2 | package org.intellij.clojure.psi.impl; 3 | 4 | import java.util.List; 5 | import org.jetbrains.annotations.*; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiElementVisitor; 9 | import com.intellij.psi.util.PsiTreeUtil; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import org.intellij.clojure.psi.*; 12 | import com.intellij.psi.tree.IElementType; 13 | 14 | public class CVecImpl extends CLVFormImpl implements CVec { 15 | 16 | public CVecImpl(@NotNull IElementType type) { 17 | super(type); 18 | } 19 | 20 | public void accept(@NotNull ClojureVisitor visitor) { 21 | visitor.visitVec(this); 22 | } 23 | 24 | public void accept(@NotNull PsiElementVisitor visitor) { 25 | if (visitor instanceof ClojureVisitor) accept((ClojureVisitor)visitor); 26 | else super.accept(visitor); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Available idea versions: 2 | # https://www.jetbrains.com/intellij-repository/releases 3 | # https://www.jetbrains.com/intellij-repository/snapshots 4 | 5 | pluginName=Clojure-Kit 6 | pluginVersion=2020.3.2-SNAPSHOT 7 | pluginSinceIdeaBuild=203.5981 8 | ideaVersion=2020.3 9 | 10 | javaVersion=11 11 | kotlinApiVersion=1.4 12 | gradleVersion=7.3.3 13 | 14 | clojureVersion=1.11.0-alpha3 15 | cljsVersion=1.11.4 16 | 17 | artifactsPath=build/artifacts 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregsh/Clojure-Kit/91ec32cf6c6835a43914e1c6ce2cca599f914167/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-7.3.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /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 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /grammars/_ClojureLexer.flex: -------------------------------------------------------------------------------- 1 | package org.intellij.clojure.parser; 2 | 3 | import com.intellij.lang.Language; 4 | import com.intellij.lexer.FlexLexer; 5 | import com.intellij.psi.tree.IElementType; 6 | import org.intellij.clojure.lang.ClojureScriptLanguage; 7 | 8 | import static com.intellij.psi.TokenType.BAD_CHARACTER; 9 | import static com.intellij.psi.TokenType.WHITE_SPACE; 10 | import static org.intellij.clojure.psi.ClojureTypes.*; 11 | import static org.intellij.clojure.lang.ClojureTokens.LINE_COMMENT; 12 | 13 | %% 14 | 15 | %{ 16 | private Language myLanguage; 17 | 18 | public _ClojureLexer(Language language) { 19 | myLanguage = language; 20 | } 21 | %} 22 | 23 | %public 24 | %class _ClojureLexer 25 | %implements FlexLexer 26 | %function advance 27 | %type IElementType 28 | %unicode 29 | 30 | %state SYMBOL0, SYMBOL1, SYMBOL2, SYMBOL3 31 | %state DISPATCH 32 | 33 | WHITE_SPACE=\s+ 34 | LINE_COMMENT=;.* 35 | STR_CHAR=[^\\\"]|\\.|\\\" 36 | STRING=\" {STR_CHAR}* \" 37 | // octal numbers: 023, 023N, but not 023M 38 | NUMBER=[+-]? [0-9]+ (N | M | {NUMBER_EXP} M? | (\.[0-9]*) {NUMBER_EXP}? M?)? // N - BigInteger, M - BigDecimal 39 | NUMBER_EXP=[eE][+-]?[0-9]+ 40 | HEXNUM=[+-]? "0x" [\da-fA-F]+ N? 41 | RADIX=[+-]? [0-9]{1,2}r[\da-zA-Z]+ 42 | RATIO=[+-]? [0-9]+"/"[0-9]+ 43 | CHARACTER=\\([btrnf]|u[0-9a-fA-F]{4}|o[0-7]{3}|backspace|tab|newline|formfeed|return|space|.) 44 | BAD_LITERAL=\" ([^\\\"]|\\.|\\\")* 45 | | [+-]? "0x" \w+ 46 | 47 | SYM_START=[[\w<>$%&=*+\-!?_|]--#\d] | ".." 48 | SYM_PART=[.]? {SYM_CHAR} | ".." 49 | SYM_CHAR=[\w<>$%&=*+\-!?_|'#] 50 | SYM_ANY={SYM_CHAR} | [./] 51 | 52 | SYM_TAIL={SYM_PART}+ (":" {SYM_PART}+)? 53 | 54 | %% 55 | { 56 | {WHITE_SPACE} { return WHITE_SPACE; } 57 | {LINE_COMMENT} { return LINE_COMMENT; } 58 | 59 | "#" { yybegin(DISPATCH); } 60 | 61 | "^" { return C_HAT; } 62 | "~@" { return C_TILDE_AT; } 63 | "~" { return C_TILDE; } 64 | "@" { return C_AT; } 65 | "(" { return C_PAREN1; } 66 | ")" { return C_PAREN2; } 67 | "[" { return C_BRACKET1; } 68 | "]" { return C_BRACKET2; } 69 | "{" { return C_BRACE1; } 70 | "}" { return C_BRACE2; } 71 | "," { return C_COMMA; } 72 | "'" { return C_QUOTE; } 73 | "`" { return C_SYNTAX_QUOTE; } 74 | 75 | "nil" { return C_NIL; } 76 | true|false { return C_BOOL; } 77 | 78 | {STRING} { return C_STRING; } 79 | {NUMBER} { return C_NUMBER; } 80 | {HEXNUM} { return C_HEXNUM; } 81 | {RADIX} { return C_RDXNUM; } 82 | {RATIO} { return C_RATIO; } 83 | {CHARACTER} { return C_CHAR; } 84 | {BAD_LITERAL} { return BAD_CHARACTER; } 85 | 86 | "::" { yybegin(SYMBOL0); return C_COLONCOLON; } 87 | ":" { yybegin(SYMBOL0); return C_COLON; } 88 | ".-" / {SYM_CHAR} { yybegin(SYMBOL0); return C_DOTDASH; } 89 | ".-" { return C_SYM; } 90 | "." / {SYM_CHAR} { yybegin(SYMBOL0); return C_DOT; } 91 | "." { return C_SYM; } 92 | "/" {SYM_ANY}+ { yybegin(YYINITIAL); return BAD_CHARACTER; } 93 | "/" { return C_SYM; } 94 | 95 | {SYM_START}{SYM_TAIL}? { yybegin(SYMBOL1); return C_SYM; } 96 | } 97 | 98 | { 99 | {SYM_TAIL} { yybegin(SYMBOL1); return C_SYM; } 100 | [^] { yybegin(YYINITIAL); yypushback(yylength()); } 101 | } 102 | 103 | { 104 | ":" { yybegin(YYINITIAL); return BAD_CHARACTER; } 105 | "/" { yybegin(SYMBOL2); return C_SLASH; } 106 | "." { yybegin(YYINITIAL); return C_DOT; } 107 | [^] { yybegin(YYINITIAL); yypushback(yylength()); } 108 | } 109 | 110 | { 111 | {SYM_TAIL} { yybegin(SYMBOL3); return C_SYM; } 112 | } 113 | 114 | { 115 | ":" { yybegin(YYINITIAL); return BAD_CHARACTER; } 116 | "." { yybegin(YYINITIAL); return C_DOT; } 117 | [^] { yybegin(YYINITIAL); yypushback(yylength()); } 118 | } 119 | 120 | { 121 | "/" {SYM_ANY}+ { yybegin(YYINITIAL); return BAD_CHARACTER; } 122 | } 123 | 124 | { 125 | "^" { yybegin(YYINITIAL); return C_SHARP_HAT; } // Meta 126 | "'" { yybegin(YYINITIAL); return C_SHARP_QUOTE; } // Var 127 | "\"" { yybegin(YYINITIAL); yypushback(1); return C_SHARP; } // Regex 128 | "(" { yybegin(YYINITIAL); yypushback(1); return C_SHARP; } // Fn 129 | "{" { yybegin(YYINITIAL); yypushback(1); return C_SHARP; } // Set 130 | "=" { yybegin(YYINITIAL); return C_SHARP_EQ; } // Eval 131 | "!" { yybegin(YYINITIAL); return C_SHARP_COMMENT; } // Comment 132 | "<" { yybegin(YYINITIAL); return BAD_CHARACTER; } // Unreadable 133 | "_" { yybegin(YYINITIAL); return C_SHARP_COMMENT; } // Discard 134 | "?@" { yybegin(YYINITIAL); return C_SHARP_QMARK_AT; } // Conditional w/ Splicing 135 | "?" { yybegin(YYINITIAL); return C_SHARP_QMARK; } // Conditional 136 | "#" { yybegin(YYINITIAL); return C_SHARP_SYM; } // Conditional 137 | ":" { yybegin(YYINITIAL); yypushback(yylength()); return C_SHARP_NS; } // Map ns prefix 138 | [\s\w] { yybegin(YYINITIAL); yypushback(yylength()); return C_SHARP; } 139 | [^] { yybegin(YYINITIAL); yypushback(yylength()); return BAD_CHARACTER; } 140 | 141 | <> { yybegin(YYINITIAL); return BAD_CHARACTER; } 142 | } 143 | 144 | [^] { return BAD_CHARACTER; } 145 | -------------------------------------------------------------------------------- /grammars/clojure.bnf: -------------------------------------------------------------------------------- 1 | { 2 | generate=[tokenAccessors="no"] 3 | parserClass='org.intellij.clojure.parser.ClojureParser' 4 | parserImports=[ 5 | 'static org.intellij.clojure.parser.ClojureParserUtil.adapt_builder_' 6 | 'static org.intellij.clojure.parser.ClojureParserUtil.*' 7 | ] 8 | psiPackage='org.intellij.clojure.psi' 9 | psiImplPackage='org.intellij.clojure.psi.impl' 10 | psiImplUtilClass='org.intellij.clojure.psi.impl.ClojurePsiImplUtil' 11 | psiClassPrefix='C' 12 | psiVisitorName='ClojureVisitor' 13 | implements='org.intellij.clojure.psi.CElement' 14 | extends='org.intellij.clojure.psi.impl.CComposite' 15 | mixin("list")="org.intellij.clojure.psi.impl.CListBase" 16 | mixin("keyword")="org.intellij.clojure.psi.impl.CKeywordBase" 17 | mixin("symbol")="org.intellij.clojure.psi.impl.CSymbolBase" 18 | 19 | elementTypeHolderClass='org.intellij.clojure.psi.ClojureTypes' 20 | elementTypeClass="org.intellij.clojure.psi.ClojureNodeType" 21 | tokenTypeClass="org.intellij.clojure.psi.ClojureTokenType" 22 | elementTypePrefix='C_' 23 | 24 | tokens=[ 25 | whitespace='regexp:\s+' 26 | //line_comment='regexp:;.*' 27 | string='regexp:"([^"]|\\")*"' 28 | number='regexp:\d\d?r[\da-zA-Z]+|M?\d+(\.\d*([eE]\d+)?)?' 29 | ratio='regexp:\d+/\d+' 30 | char='regexp:\\(u\d{4}|newline|space|backspace|return|.)' 31 | bool="regexp:true|false" 32 | nil='nil' 33 | sym="regexp:[\w.<>$%&=*/+\-!?_'[^\d]][\w.<>$%&=*/+\-!?_']*((:[\w<>$%&=*/+\-!?_'])+)?" 34 | sharp_hat="#^" 35 | sharp_quote="#'" 36 | sharp_comment="#_" 37 | sharp_qmark="#?" 38 | sharp_qmark_at="#?@" 39 | sharp_eq="#=" 40 | sharp_ns="#:" 41 | sharp_sym="##" 42 | 43 | paren1='(' 44 | paren2=')' 45 | bracket1='[' 46 | bracket2=']' 47 | brace1='{' 48 | brace2='}' 49 | colon=':' 50 | coloncolon='::' 51 | comma=',' 52 | quote="'" 53 | syntax_quote="`" 54 | sharp="#" 55 | hat="^" 56 | tilde="~" 57 | tilde_at="~@" 58 | at="@" 59 | 60 | dot='.' 61 | dotdash='.-' 62 | slash='/' 63 | ] 64 | extends("p_form|s_form")=form 65 | extends("set|map|constructor|l_v_form")=p_form 66 | extends("vec|list")=l_v_form 67 | extends("fun")=list 68 | extends("symbol|keyword|literal|access")=s_form 69 | extends("regexp")=literal 70 | extends("symbol_.*")=symbol 71 | elementType("symbol_.*")=symbol 72 | elementType("access_.*")=access 73 | pin("list|set|vec|map|fun")="'[\(\[\{]'" 74 | pin("constructor|reader_cond")=1 75 | name("metadata|constructor|reader_.*")=form 76 | 77 | methods("reader_macro|metadata")=[toString] 78 | consumeTokenMethod("commented|symbol_nsq")="fast" 79 | } 80 | 81 | root ::= <> 82 | //root ::= entry * // for LivePreview 83 | private root_entry ::= not_eof (commented | form) {pin=1 recoverWhile=root_entry_recover} 84 | private external root_entry_recover ::= rootFormRecover 85 | private not_eof ::= !<> 86 | 87 | form ::= form_prefix form_prefix * form_upper | form_inner 88 | {pin(".*")=1 methods=[form="" commented="" metas="metadata" readerMacros="reader_macro" toString]} 89 | private form_prefix ::= metadata | reader_macro | commented 90 | private external form_recover ::= formRecover 91 | commented ::= "#_" form {pin=1} 92 | private skip ::= commented * 93 | 94 | upper form_upper ::= form_inner {elementType=form name=form} 95 | private form_inner ::= p_forms | s_forms | constructor 96 | private p_forms ::= list | set | vec | map | fun 97 | private s_forms ::= symbol access_left? | keyword | literal | regexp | access 98 | 99 | fake p_form ::= form * {methods=[forms="form"]} 100 | fake l_v_form ::= 101 | fake s_form ::= 102 | list ::= '(' list_body ')' 103 | {methods=[getTextOffset getFirst]} 104 | set ::= '#' <> '{' set_body '}' 105 | vec ::= '[' vec_body ']' 106 | map ::= '{' map_body '}' 107 | fun ::= '#' <> '(' list_body ')' 108 | symbol ::= symbol_qualified 109 | {methods=[getName getQualifiedName getQualifier getTextOffset getReference]} 110 | keyword ::= (':' | '::') <> symbol_qualified 111 | {methods=[getName getNamespace getQualifiedName getTextOffset]} 112 | private symbol_qualified ::= symbol_plain symbol_nsq? 113 | symbol_plain ::= sym 114 | left symbol_nsq ::= '/' sym 115 | literal ::= number | hexnum | rdxnum | ratio | bool | nil | string | char 116 | {methods=[getLiteralType getLiteralText]} 117 | regexp ::= '#' <> string {extends=literal} 118 | access ::= ('.' | '.-') symbol 119 | left access_left ::= !<> '.' 120 | constructor ::= '#' skip symbol skip form 121 | metadata ::= ("^" | "#^") (string | symbol | keyword | map) 122 | reader_macro ::= "'" | "~" | "~@" | "@" | "`" | "#'" | "#=" | symbolic_value | reader_cond | map_ns_prefix 123 | private symbolic_value ::= '##' &sym {pin=1} 124 | private reader_cond ::= ('#?' | '#?@') &'(' {pin(".*")=1} 125 | private map_ns_prefix ::= "#:" (':' <> symbol_plain 126 | | alias_condition '::' <> symbol_plain 127 | | '::' ) &'{' 128 | {pin(".*")=1} 129 | private alias_condition ::= &('::' sym) 130 | 131 | private meta items ::= <> <>>> * {recoverWhile="<>"} 132 | private meta items_entry ::= (not_eof <>) (commented | <>) {pin=1 recoverWhile=form_recover} 133 | private list_body ::= <> 134 | private set_body ::= <> 135 | private vec_body ::= <> 136 | private map_body ::= <> 137 | private map_entry ::= form skip form {pin=2} -------------------------------------------------------------------------------- /resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Class-Path: kotlin-runtime.jar kotlin-reflect.jar clojure-1.8.0.jar cl 3 | ojure-jsr223-1.5.1.jar 4 | 5 | -------------------------------------------------------------------------------- /resources/META-INF/plugin-copyright.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /resources/META-INF/plugin-java.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /resources/colorSchemes/ClojureDarcula.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 13 | 19 | 24 | 29 | 34 | -------------------------------------------------------------------------------- /resources/colorSchemes/ClojureDefault.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 14 | 19 | 24 | 29 | -------------------------------------------------------------------------------- /resources/icons/clojure.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 36 | 38 | 39 | 41 | image/svg+xml 42 | 44 | 45 | 46 | 47 | 48 | 50 | 55 | 58 | 63 | 68 | 73 | 78 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /resources/icons/clojureFile.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /resources/icons/namespace.svg: -------------------------------------------------------------------------------- 1 | 2 | function 3 | 4 | 5 | 6 | n 7 | 8 | -------------------------------------------------------------------------------- /resources/icons/symbol.svg: -------------------------------------------------------------------------------- 1 | 2 | function 3 | 4 | 5 | 6 | s 7 | 8 | -------------------------------------------------------------------------------- /resources/inspectionDescriptions/ClojureResolveInspection.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
This inspection reports unresolved references.
8 | 9 | -------------------------------------------------------------------------------- /resources/liveTemplates/clojureLiveTemplates.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /resources/messages/ClojureBundle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016-present Greg Shrago 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # 17 | 18 | clojure.inspections.group.name=Clojure 19 | inspection.name.resolve=Unresolved reference -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'clojure-kit' 2 | 3 | -------------------------------------------------------------------------------- /src/lang/clojure-inspections.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.inspections 19 | 20 | import com.intellij.codeInspection.* 21 | import com.intellij.openapi.util.Key 22 | import com.intellij.psi.PsiElement 23 | import com.intellij.psi.PsiPolyVariantReference 24 | import org.intellij.clojure.ClojureConstants 25 | import org.intellij.clojure.ClojureConstants.SYMBOLIC_VALUES 26 | import org.intellij.clojure.psi.* 27 | import org.intellij.clojure.psi.impl.* 28 | import org.intellij.clojure.tools.Tool 29 | import org.intellij.clojure.util.* 30 | import kotlin.collections.component1 31 | import kotlin.collections.component2 32 | 33 | /** 34 | * @author gregsh 35 | */ 36 | val RESOLVE_SKIPPED: Key = Key.create("C_SKIP_RESOLVE") 37 | 38 | class ClojureInspectionSuppressor : InspectionSuppressor { 39 | override fun getSuppressActions(element: PsiElement?, toolId: String): Array { 40 | return arrayOf() 41 | } 42 | 43 | override fun isSuppressedFor(element: PsiElement, toolId: String): Boolean { 44 | if (!toolId.startsWith("Clojure")) return false 45 | // todo 46 | return false 47 | } 48 | } 49 | 50 | class ClojureResolveInspection : LocalInspectionTool() { 51 | override fun getDisplayName() = "Unresolved reference" 52 | override fun getShortName() = "ClojureResolveInspection" 53 | 54 | override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): ClojureVisitor { 55 | if (Tool.choose(holder.file.name) != null) return ClojureVisitor() 56 | 57 | return object : ClojureVisitor() { 58 | override fun visitSymbol(o: CSymbol) { 59 | val reference = o.reference 60 | val multiResolve = (reference as PsiPolyVariantReference).multiResolve(false) 61 | if (o.getUserData(RESOLVE_SKIPPED) != null) return 62 | 63 | val checkBadNS = { it : PsiElement? -> o.parent !is CSymbol && 64 | it.asCTarget?.key?.run { type == "ns" && namespace == "" } == true && 65 | it.forceXTarget.let { it != null && !it.canNavigate() }} 66 | val (valid, invalid, badNS) = multiResolve.jbIt().reduce(arrayOf(0, 0, 0)) { arr, it -> arr[if (it.isValidResult) if (checkBadNS(it.element)) 2 else 0 else 1] ++; arr } 67 | 68 | val qualifier = reference.qualifier?.apply { 69 | if (this.reference?.resolve() == null) return } 70 | 71 | val langKind = (holder.file as CFileImpl).placeLanguage(o) 72 | val isCljS = langKind == Dialect.CLJS 73 | 74 | if (valid != 0) return 75 | if (qualifier == null && !isCljS && ClojureConstants.TYPE_META_ALIASES.contains(o.name)) return 76 | if (qualifier == null && isCljS && ClojureConstants.CLJS_TYPES.contains(o.name)) return 77 | if (o.parent is CSymbol && o.parent.parent is CKeyword && 78 | o.parent.prevSibling?.elementType == ClojureTypes.C_COLON) return 79 | val quotesAndComments = o.parents().filter { 80 | it is CMetadata || 81 | it.fastFlagIsSet(FLAG_COMMENTED) || 82 | it is CReaderMacro && it.firstChild.elementType == ClojureTypes.C_SHARP_NS || 83 | it.role != Role.RCOND && it.iterate(CReaderMacro::class).find { suppressResolve(it, invalid != 0, badNS != 0) } != null 84 | }.first() 85 | if (quotesAndComments != null) return 86 | holder.registerProblem(reference, "unable to resolve '${reference.referenceName}'", ProblemHighlightType.GENERIC_ERROR_OR_WARNING) 87 | } 88 | } 89 | } 90 | } 91 | 92 | private fun suppressResolve(o: CReaderMacro, invalid: Boolean, badNS : Boolean) = when (o.firstChild.elementType) { 93 | ClojureTypes.C_QUOTE -> !badNS 94 | ClojureTypes.C_SYNTAX_QUOTE -> true 95 | ClojureTypes.C_SHARP_QUOTE -> invalid || badNS 96 | ClojureTypes.C_SHARP_SYM -> SYMBOLIC_VALUES.contains((o.parent as? CSymbol)?.name) 97 | else -> false 98 | } 99 | 100 | -------------------------------------------------------------------------------- /src/lang/clojure-language.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.lang 19 | 20 | import com.intellij.codeInsight.template.FileTypeBasedContextType 21 | import com.intellij.ide.actions.QualifiedNameProvider 22 | import com.intellij.lang.BracePair 23 | import com.intellij.lang.Language 24 | import com.intellij.lang.PairedBraceMatcher 25 | import com.intellij.openapi.fileTypes.LanguageFileType 26 | import com.intellij.openapi.project.Project 27 | import com.intellij.openapi.vfs.VirtualFile 28 | import com.intellij.psi.LanguageSubstitutor 29 | import com.intellij.psi.PsiElement 30 | import com.intellij.psi.PsiFile 31 | import com.intellij.psi.TokenType 32 | import com.intellij.psi.tree.IElementType 33 | import com.intellij.psi.tree.IFileElementType 34 | import com.intellij.psi.tree.TokenSet 35 | import org.intellij.clojure.ClojureConstants 36 | import org.intellij.clojure.ClojureIcons 37 | import org.intellij.clojure.psi.CKeyword 38 | import org.intellij.clojure.psi.CSymbol 39 | import org.intellij.clojure.psi.ClojureTypes.* 40 | import org.intellij.clojure.psi.SymKey 41 | import org.intellij.clojure.psi.impl.ClojureDefinitionService 42 | import org.intellij.clojure.psi.impl.asCTarget 43 | import org.intellij.clojure.psi.impl.resolveInfo 44 | import org.intellij.clojure.util.qualifiedName 45 | import org.intellij.clojure.util.thisForm 46 | 47 | /** 48 | * @author gregsh 49 | */ 50 | object ClojureFileType : LanguageFileType(ClojureLanguage) { 51 | override fun getIcon() = ClojureIcons.FILE 52 | override fun getName() = "Clojure" 53 | override fun getDefaultExtension() = ClojureConstants.CLJ 54 | override fun getDescription() = "Clojure and ClojureScript" 55 | } 56 | 57 | object ClojureLanguage : Language("Clojure") 58 | 59 | object ClojureScriptLanguage : Language(ClojureLanguage, "ClojureScript") 60 | 61 | class ClojureLanguageSubstitutor : LanguageSubstitutor() { 62 | override fun getLanguage(file: VirtualFile, project: Project): Language? { 63 | return if (file.extension?.equals(ClojureConstants.CLJS) == true) 64 | ClojureScriptLanguage 65 | else null 66 | } 67 | } 68 | 69 | class ClojureBraceMatcher : PairedBraceMatcher { 70 | 71 | override fun getPairs() = ClojureTokens.BRACE_PAIRS.toTypedArray() 72 | override fun getCodeConstructStart(file: PsiFile, openingBraceOffset: Int) = openingBraceOffset 73 | override fun isPairedBracesAllowedBeforeType(lbraceType: IElementType, tokenType: IElementType?) = tokenType === null 74 | || ClojureTokens.WHITESPACES.contains(tokenType) || ClojureTokens.COMMENTS.contains(tokenType) 75 | || tokenType === C_COMMA || tokenType === C_PAREN2 76 | || tokenType === C_BRACE2 || tokenType === C_BRACKET2 77 | } 78 | 79 | class ClojureQualifiedNameProvider : QualifiedNameProvider { 80 | override fun getQualifiedName(element: PsiElement?): String? { 81 | return element.asCTarget?.key?.run { if (type == "keyword") ":$qualifiedName" else qualifiedName } 82 | } 83 | 84 | override fun qualifiedNameToElement(fqn: String, project: Project): PsiElement? { 85 | val idx = fqn.indexOf('/') 86 | val name = fqn.substring(idx + 1) 87 | val ns = if (idx == -1) "" else fqn.substring(0, idx) 88 | return ClojureDefinitionService.getInstance(project).getDefinition(SymKey(name, ns, "def")) 89 | } 90 | 91 | override fun adjustElementToCopy(element: PsiElement) = when { 92 | element.asCTarget != null -> element 93 | else -> element.thisForm.let { 94 | when (it) { 95 | is CSymbol -> { 96 | val def = it.resolveInfo() 97 | if (def != null) ClojureDefinitionService.getInstance(element.project).getDefinition(SymKey(def)) else null 98 | } 99 | is CKeyword -> ClojureDefinitionService.getInstance(element.project).getKeyword(it) 100 | else -> null 101 | } 102 | } 103 | } 104 | } 105 | 106 | class ClojureLiveTemplateContext : FileTypeBasedContextType("Clojure", "Clojure", ClojureFileType) 107 | 108 | object ClojureTokens { 109 | @JvmField val CLJ_FILE_TYPE = IFileElementType("CLOJURE_FILE", ClojureLanguage) 110 | @JvmField val CLJS_FILE_TYPE = IFileElementType("CLOJURE_SCRIPT_FILE", ClojureScriptLanguage) 111 | 112 | @JvmField val LINE_COMMENT = IElementType("C_LINE_COMMENT", ClojureLanguage) 113 | 114 | @JvmField val WHITESPACES = TokenSet.create(C_COMMA, TokenType.WHITE_SPACE) 115 | @JvmField val COMMENTS = TokenSet.create(LINE_COMMENT) 116 | @JvmField val STRINGS = TokenSet.create(C_STRING) 117 | @JvmField val SYM_ALIKE = TokenSet.create(C_BOOL, C_NIL, C_SYM) 118 | @JvmField val LITERALS = TokenSet.create(C_BOOL, C_CHAR, C_HEXNUM, C_NIL, C_NUMBER, C_RATIO, C_RDXNUM, C_STRING) 119 | 120 | @JvmField val SHARPS = TokenSet.create(C_SHARP, C_SHARP_COMMENT, C_SHARP_QMARK, C_SHARP_QMARK_AT, C_SHARP_EQ, C_SHARP_HAT, 121 | C_SHARP_QUOTE, C_SHARP_NS, C_SHARP_SYM) 122 | @JvmField val MACROS = TokenSet.create(C_AT, C_COLON, C_COLONCOLON, C_HAT, C_QUOTE, C_SYNTAX_QUOTE, C_TILDE, C_TILDE_AT) 123 | 124 | @JvmField val PAREN1_ALIKE = TokenSet.create(C_PAREN1, C_BRACE1, C_BRACKET1) 125 | @JvmField val PAREN2_ALIKE = TokenSet.create(C_PAREN2, C_BRACE2, C_BRACKET2) 126 | @JvmField val PAREN_ALIKE = TokenSet.orSet(PAREN1_ALIKE, PAREN2_ALIKE) 127 | @JvmField val LIST_ALIKE = TokenSet.create(C_FUN, C_LIST, C_MAP, C_SET, C_VEC) 128 | 129 | @JvmField val FORMS = TokenSet.create(C_CONSTRUCTOR, C_FORM, C_FUN, C_KEYWORD, 130 | C_LIST, C_LITERAL, C_MAP, C_REGEXP, 131 | C_SET, C_SYMBOL, C_VEC) 132 | 133 | @JvmField val BRACE_PAIRS = listOf( 134 | BracePair(C_PAREN1, C_PAREN2, false), 135 | BracePair(C_BRACE1, C_BRACE2, false), 136 | BracePair(C_BRACKET1, C_BRACKET2, false)) 137 | } 138 | -------------------------------------------------------------------------------- /src/lang/clojure-parser.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.parser 19 | 20 | import com.intellij.lang.* 21 | import com.intellij.lang.parser.GeneratedParserUtilBase 22 | import com.intellij.lexer.FlexAdapter 23 | import com.intellij.lexer.Lexer 24 | import com.intellij.lexer.LookAheadLexer 25 | import com.intellij.openapi.project.Project 26 | import com.intellij.psi.FileViewProvider 27 | import com.intellij.psi.TokenType 28 | import com.intellij.psi.impl.source.tree.CompositeElement 29 | import com.intellij.psi.tree.IElementType 30 | import com.intellij.psi.tree.TokenSet 31 | import org.intellij.clojure.lang.ClojureTokens 32 | import org.intellij.clojure.psi.ClojureTypes.* 33 | import org.intellij.clojure.psi.impl.CFileImpl 34 | import org.intellij.clojure.util.wsOrComment 35 | 36 | /** 37 | * @author gregsh 38 | */ 39 | class ClojureLexer(language: Language) : LookAheadLexer(FlexAdapter(_ClojureLexer(language))) { 40 | override fun lookAhead(baseLexer: Lexer) { 41 | val tokenType0 = baseLexer.tokenType 42 | val tokenEnd0 = baseLexer.tokenEnd 43 | when (tokenType0) { 44 | in ClojureTokens.LITERALS -> { 45 | baseLexer.advance() 46 | val tokenType = baseLexer.tokenType 47 | if (tokenType0 == C_NUMBER && ClojureTokens.SYM_ALIKE.contains(tokenType) || 48 | tokenType0 == C_CHAR && (tokenType == C_SYM || ClojureTokens.LITERALS.contains(tokenType))) { 49 | advanceAs(baseLexer, TokenType.BAD_CHARACTER) 50 | } 51 | else { 52 | addToken(tokenEnd0, tokenType0) 53 | } 54 | } 55 | else -> super.lookAhead(baseLexer) 56 | } 57 | } 58 | } 59 | 60 | class ClojureParserDefinition : ClojureParserDefinitionBase() { 61 | override fun getFileNodeType() = ClojureTokens.CLJ_FILE_TYPE 62 | } 63 | 64 | class ClojureScriptParserDefinition : ClojureParserDefinitionBase() { 65 | override fun getFileNodeType() = ClojureTokens.CLJS_FILE_TYPE 66 | } 67 | 68 | class ClojureASTFactory : ASTFactory() { 69 | override fun createComposite(type: IElementType): CompositeElement? = Factory.createElement(type) 70 | } 71 | 72 | abstract class ClojureParserDefinitionBase : ParserDefinition { 73 | 74 | override fun createLexer(project: Project?) = ClojureLexer(fileNodeType.language) 75 | override fun createParser(project: Project?) = ClojureParser() 76 | override fun createFile(viewProvider: FileViewProvider) = CFileImpl(viewProvider!!, fileNodeType.language) 77 | override fun createElement(node: ASTNode?) = throw UnsupportedOperationException( 78 | "$node" + (node?.elementType?.language ?: fileNodeType.language).let { 79 | "; ASTFactory(${it.id})=${LanguageASTFactory.INSTANCE.forLanguage(it)}" 80 | }) 81 | 82 | override fun getStringLiteralElements() = ClojureTokens.STRINGS 83 | override fun getWhitespaceTokens() = ClojureTokens.WHITESPACES 84 | override fun getCommentTokens() = ClojureTokens.COMMENTS 85 | 86 | override fun spaceExistanceTypeBetweenTokens(left: ASTNode, right: ASTNode): ParserDefinition.SpaceRequirements { 87 | val lt = left.elementType 88 | val rt = right.elementType 89 | if (rt == C_COMMA || ClojureTokens.MACROS.contains(lt) || ClojureTokens.SHARPS.contains(lt)) { 90 | return ParserDefinition.SpaceRequirements.MUST_NOT 91 | } 92 | if (lt == C_DOT || rt == C_DOT || lt == C_DOTDASH || 93 | lt == C_SLASH && rt == C_SYM || 94 | lt == C_SYM && rt == C_SLASH) { 95 | return ParserDefinition.SpaceRequirements.MUST_NOT 96 | } 97 | for (p in ClojureTokens.BRACE_PAIRS) { 98 | if (lt == p.leftBraceType || rt == p.rightBraceType) { 99 | return ParserDefinition.SpaceRequirements.MAY 100 | } 101 | } 102 | return ParserDefinition.SpaceRequirements.MUST 103 | } 104 | } 105 | 106 | class ClojureParserUtil { 107 | @Suppress("UNUSED_PARAMETER") 108 | companion object { 109 | @JvmStatic 110 | fun adapt_builder_(root: IElementType, builder: PsiBuilder, parser: PsiParser, extendsSets: Array?): PsiBuilder = 111 | GeneratedParserUtilBase.adapt_builder_(root, builder, parser, extendsSets).apply { 112 | (this as? GeneratedParserUtilBase.Builder)?.state?.braces = null 113 | } 114 | 115 | @JvmStatic 116 | fun parseTree(b: PsiBuilder, l: Int, p: GeneratedParserUtilBase.Parser) = 117 | GeneratedParserUtilBase.parseAsTree(GeneratedParserUtilBase.ErrorState.get(b), b, l, 118 | GeneratedParserUtilBase.DUMMY_BLOCK, false, p, GeneratedParserUtilBase.TRUE_CONDITION) 119 | 120 | @JvmStatic 121 | fun nospace(b: PsiBuilder, l: Int): Boolean { 122 | if (space(b, l)) { 123 | b.mark().apply { b.tokenType; error("no allowed") } 124 | .setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER) 125 | } 126 | return true 127 | } 128 | 129 | @JvmStatic 130 | fun space(b: PsiBuilder, l: Int): Boolean { 131 | return b.rawLookup(0).wsOrComment() || b.rawLookup(-1).wsOrComment() 132 | } 133 | 134 | private val RECOVER_SET = TokenSet.orSet( 135 | ClojureTokens.SHARPS, ClojureTokens.MACROS, ClojureTokens.PAREN_ALIKE, ClojureTokens.LITERALS, 136 | TokenSet.create(C_DOT, C_DOTDASH, C_SYM)) 137 | 138 | @JvmStatic 139 | fun formRecover(b: PsiBuilder, l: Int): Boolean { 140 | return !RECOVER_SET.contains(b.tokenType) 141 | } 142 | 143 | @JvmStatic 144 | fun rootFormRecover(b: PsiBuilder, l: Int): Boolean { 145 | val type = b.tokenType 146 | return ClojureTokens.PAREN2_ALIKE.contains(type) || !RECOVER_SET.contains(type) 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/lang/clojure-psi-api.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.psi 19 | 20 | import com.intellij.psi.NavigatablePsiElement 21 | import com.intellij.psi.PsiCodeFragment 22 | import com.intellij.psi.PsiElement 23 | import com.intellij.psi.PsiFile 24 | import com.intellij.psi.impl.source.tree.LeafPsiElement 25 | import com.intellij.psi.tree.IElementType 26 | import com.intellij.psi.tree.ILeafElementType 27 | import com.intellij.util.containers.JBIterable 28 | import org.intellij.clojure.ClojureConstants 29 | import org.intellij.clojure.lang.ClojureLanguage 30 | 31 | enum class Dialect(val coreNs: String) { 32 | CLJ(ClojureConstants.CLOJURE_CORE), 33 | CLJS(ClojureConstants.CLJS_CORE), 34 | CLJR(ClojureConstants.CLOJURE_CORE) 35 | } 36 | 37 | enum class Role { 38 | NONE, DEF, NS, NAME, 39 | RCOND, RCOND_S, 40 | PROTOTYPE, 41 | ARG_VEC, BND_VEC, FIELD_VEC, BODY, 42 | ARG, BND, FIELD // currently not set 43 | } 44 | 45 | const val FLAG_COMMENTED = 0x1 46 | const val FLAG_QUOTED = 0x2 47 | const val FLAG_UNQUOTED = 0x4 48 | 49 | interface CElement : NavigatablePsiElement { 50 | val role: Role 51 | val def: IDef? 52 | val resolvedNs: String? 53 | val flags: Int 54 | } 55 | 56 | interface ClojureElementType 57 | class ClojureTokenType(name: String) : IElementType(name, ClojureLanguage), ILeafElementType { 58 | override fun createLeafNode(leafText: CharSequence) = CToken(this, leafText) 59 | } 60 | class ClojureNodeType(name: String) : IElementType(name, ClojureLanguage), ClojureElementType 61 | class CToken(tokenType: ClojureTokenType, text: CharSequence) : LeafPsiElement(tokenType, text) 62 | 63 | interface CFile : PsiFile { 64 | val namespace: String 65 | 66 | fun defs(dialect: Dialect = Dialect.CLJ): JBIterable 67 | } 68 | 69 | interface CCodeFragment : CFile, PsiCodeFragment { 70 | fun setContext(context: PsiElement?) 71 | } 72 | 73 | interface IDef { 74 | val type: String 75 | val name: String 76 | val namespace: String 77 | } 78 | 79 | data class SymKey( 80 | override val name: String, 81 | override val namespace: String, 82 | override val type: String 83 | ) : IDef { 84 | constructor(def : IDef): this(def.name, def.namespace, def.type) 85 | } 86 | 87 | class Def( 88 | val key: SymKey, 89 | val protos: List, 90 | val meta: Map 91 | ) : IDef by key 92 | 93 | class Prototype(val args: List, val typeHint: String?) 94 | 95 | class Arg(val name: String, val typeHint: String?) 96 | 97 | -------------------------------------------------------------------------------- /src/lang/clojure-psi-fragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.lang 19 | 20 | import com.intellij.lang.ASTNode 21 | import com.intellij.lang.Language 22 | import com.intellij.lang.LanguageParserDefinitions 23 | import com.intellij.lang.PsiBuilderFactory 24 | import com.intellij.openapi.project.Project 25 | import com.intellij.psi.FileViewProvider 26 | import com.intellij.psi.PsiElement 27 | import com.intellij.psi.SingleRootFileViewProvider 28 | import com.intellij.psi.TokenType 29 | import com.intellij.psi.impl.PsiManagerEx 30 | import com.intellij.psi.impl.source.tree.FileElement 31 | import com.intellij.psi.impl.source.tree.TreeElement 32 | import com.intellij.psi.search.GlobalSearchScope 33 | import com.intellij.psi.tree.IElementType 34 | import com.intellij.psi.tree.IFileElementType 35 | import com.intellij.testFramework.LightVirtualFile 36 | import org.intellij.clojure.psi.CCodeFragment 37 | import org.intellij.clojure.psi.CFile 38 | import org.intellij.clojure.psi.impl.CFileImpl 39 | 40 | /** 41 | * @author gregsh 42 | */ 43 | fun newCodeFragment(project: Project, 44 | language: Language, 45 | elementType: IElementType, 46 | fileName: String, 47 | text: CharSequence, 48 | context: PsiElement?, 49 | isPhysical: Boolean): CCodeFragment { 50 | val file = LightVirtualFile(fileName, language, text) 51 | val viewProvider = PsiManagerEx.getInstanceEx(project).fileManager.createFileViewProvider(file, isPhysical) 52 | val fragment = CCodeFragmentImpl(viewProvider, language, elementType, isPhysical) 53 | fragment.context = context 54 | return fragment 55 | } 56 | 57 | open class CCodeFragmentImpl( 58 | viewProvider: FileViewProvider, 59 | language: Language, 60 | val elementType: IElementType, 61 | private var myPhysical: Boolean?) 62 | : CFileImpl(viewProvider, language), CCodeFragment { 63 | private var myViewProvider: FileViewProvider? = null 64 | private var myContext: PsiElement? = null 65 | private var myScope: GlobalSearchScope? = null 66 | override val namespace: String 67 | get() = (context?.containingFile as? CFile)?.namespace ?: super.namespace 68 | 69 | init { 70 | (viewProvider as SingleRootFileViewProvider).forceCachedPsi(this) 71 | init(TokenType.CODE_FRAGMENT, CCodeFragmentElementType(language, elementType)) 72 | } 73 | 74 | override fun isPhysical() = myPhysical ?: super.isPhysical() 75 | override fun getViewProvider() = myViewProvider ?: super.getViewProvider() 76 | 77 | override fun getContext() = if (myContext?.isValid == true) myContext else super.getContext() 78 | override fun setContext(context: PsiElement?) { 79 | myContext = context 80 | } 81 | 82 | override fun getForcedResolveScope() = myScope 83 | override fun forceResolveScope(scope: GlobalSearchScope) { 84 | myScope = scope 85 | } 86 | 87 | override fun clone(): CCodeFragmentImpl { 88 | val clone = cloneImpl(calcTreeElement().clone() as FileElement) as CCodeFragmentImpl 89 | clone.myPhysical = false 90 | clone.myOriginalFile = this 91 | val fileManager = (manager as PsiManagerEx).fileManager 92 | val fileClone = LightVirtualFile(name, language, text) 93 | val cloneViewProvider = fileManager.createFileViewProvider(fileClone, false) as SingleRootFileViewProvider 94 | clone.myViewProvider = cloneViewProvider 95 | cloneViewProvider.forceCachedPsi(clone) 96 | clone.init(TokenType.CODE_FRAGMENT, contentElementType) 97 | return clone 98 | } 99 | } 100 | 101 | class CCodeFragmentElementType constructor(language: Language, val elementType: IElementType) : 102 | IFileElementType("CLOJURE_CODE_FRAGMENT", language, false) { 103 | 104 | override fun parseContents(chameleon: ASTNode): ASTNode? { 105 | val project = (chameleon as TreeElement).manager.project 106 | val languageForParser = language 107 | val builder = PsiBuilderFactory.getInstance().createBuilder(project, chameleon, null, languageForParser, chameleon.chars) 108 | val parser = LanguageParserDefinitions.INSTANCE.forLanguage(languageForParser).createParser(project) 109 | val node = parser.parse(elementType, builder) 110 | return if (elementType is IFileElementType) node.firstChildNode else node 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/lang/clojure-psi-genimpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.psi.impl 19 | 20 | import com.intellij.navigation.ItemPresentation 21 | import com.intellij.openapi.project.Project 22 | import com.intellij.openapi.util.text.StringUtil 23 | import com.intellij.psi.* 24 | import com.intellij.psi.impl.source.tree.CompositePsiElement 25 | import com.intellij.psi.tree.IElementType 26 | import com.intellij.psi.util.PsiUtilCore 27 | import org.intellij.clojure.ClojureIcons 28 | import org.intellij.clojure.getIconForType 29 | import org.intellij.clojure.lang.ClojureLanguage 30 | import org.intellij.clojure.psi.* 31 | import org.intellij.clojure.util.* 32 | import javax.swing.Icon 33 | 34 | /** 35 | * 36 | * 37 | * @author gregsh 38 | */ 39 | class ClojurePsiImplUtil { 40 | companion object { 41 | @JvmStatic fun toString(o: PsiElement) = "${StringUtil.getShortName(o::class.java)}(${PsiUtilCore.getElementType(o)})" 42 | 43 | @JvmStatic fun getReference(o: CSymbolBase): PsiQualifiedReference = o.refImpl!! 44 | @JvmStatic fun getName(o: CSymbolBase): String = o.lastChild.text 45 | @JvmStatic fun getTextOffset(o: CSymbolBase): Int = o.lastChild.textRange.startOffset 46 | @JvmStatic fun getQualifier(o: CSymbolBase): CSymbol? = o.lastChild.findPrev(CSymbol::class) 47 | 48 | @JvmStatic fun getQualifiedName(o: CSymbol): String { 49 | val offset = o.qualifier?.textRange?.startOffset ?: o.findChild(CToken::class)!!.textRange.startOffset 50 | val delta = if (o.lastChild.node.elementType == ClojureTypes.C_DOT) -1 else 0 51 | return o.text.let { it.substring(offset - o.textRange.startOffset, it.length + delta) } 52 | } 53 | 54 | @JvmStatic fun getName(o: CKeywordBase): String = o.symbol.name 55 | @JvmStatic fun getNamespace(o: CKeywordBase): String = o.resolvedNs!! 56 | 57 | @JvmStatic fun getTextOffset(o: CKeywordBase): Int = o.symbol.textOffset 58 | 59 | @JvmStatic fun getTextOffset(o: CListBase): Int = 60 | (o.findChild(Role.NAME) ?: o.firstForm)?.textOffset 61 | ?: o.textRange.startOffset 62 | 63 | @JvmStatic fun getFirst(o: CList): CSymbol? = o.childForm(CForm::class) as? CSymbol 64 | @JvmStatic fun getLiteralType(o: CLiteral): IElementType? = o.lastChild?.elementType 65 | @JvmStatic fun getLiteralText(o: CLiteral): String = o.lastChild?.text ?: "" 66 | } 67 | } 68 | 69 | open class CComposite(tokenType: IElementType) : CompositePsiElement(tokenType), CElement { 70 | override val role: Role get() = role(data) 71 | override val flags: Int get() = role.run { flagsImpl } 72 | override val def: IDef? get() = data as? IDef 73 | override val resolvedNs: String? get() = data as? String 74 | 75 | @JvmField internal var dataImpl: Any? = null 76 | @JvmField internal var flagsImpl: Int = 0 77 | 78 | internal val roleImpl: Role get() = role(dataImpl) 79 | internal val data: Any get() = dataImpl ?: (containingFile as CFileImpl).checkState().let { 80 | dataImpl ?: Role.NONE.also { dataImpl = it } 81 | } 82 | 83 | private fun role(data: Any?): Role = when (data) { 84 | is Role -> data 85 | is Imports, is NSDef -> Role.NS 86 | is IDef -> Role.DEF 87 | else -> Role.NONE 88 | } 89 | } 90 | 91 | abstract class CListBase(nodeType: IElementType) : CLVFormImpl(nodeType), CList, ItemPresentation { 92 | 93 | override fun getPresentation() = this 94 | override fun getIcon(unused: Boolean): Icon? = when (role) { 95 | Role.NS -> ClojureIcons.NAMESPACE 96 | Role.DEF -> getIconForType(def!!.type) 97 | Role.FIELD -> ClojureIcons.FIELD 98 | else -> null 99 | } 100 | override fun getLocationString() = containingFile.name 101 | override fun getPresentableText(): String { 102 | val prefix = iterate().takeWhile { it is CReaderMacro }.joinToString(separator = " ") { it.text } 103 | val first = this.first ?: return prefix 104 | return "$prefix(${first.name} …)" 105 | } 106 | } 107 | 108 | abstract class CKeywordBase(nodeType: IElementType) : CFormImpl(nodeType), CKeyword, 109 | PsiNameIdentifierOwner, PsiQualifiedNamedElement, ItemPresentation { 110 | 111 | abstract override fun getName(): String 112 | 113 | override fun getPresentation() = this 114 | override fun getIcon(unused: Boolean): Icon? = null 115 | override fun getLocationString() = containingFile.name 116 | override fun getNameIdentifier() = lastChild!! 117 | override fun setName(newName: String): PsiElement { 118 | nameIdentifier.replace(newLeafPsiElement(project, newName)) 119 | return this 120 | } 121 | 122 | override fun getPresentableText() = ":$qualifiedName" 123 | override fun getQualifiedName() = name.withNamespace(namespace) 124 | } 125 | 126 | abstract class CSymbolBase(nodeType: IElementType) : CSFormImpl(nodeType), CSymbol { 127 | 128 | abstract override fun getName(): String 129 | abstract override fun getReference(): PsiQualifiedReference 130 | 131 | internal var refImpl: PsiQualifiedReference? = null 132 | get() = field ?: CSymbolReference(this).apply { field = this } 133 | 134 | override fun clearCaches() { 135 | super.clearCaches() 136 | refImpl = null 137 | } 138 | } 139 | 140 | fun newLeafPsiElement(project: Project, s: String): PsiElement = 141 | PsiFileFactory.getInstance(project).createFileFromText(ClojureLanguage, s).firstChild.lastChild 142 | 143 | 144 | val PsiElement?.fastRole: Role get() = (this as? CComposite)?.roleImpl ?: Role.NONE 145 | val PsiElement?.fastFlags: Int get() = (this as? CComposite)?.flagsImpl ?: 0 146 | fun PsiElement?.fastFlagIsSet(flag: Int): Boolean = fastFlags and flag == flag 147 | val CList?.fastDef: IDef? 148 | get() = (this as? CListBase)?.run { 149 | ((this as CComposite).dataImpl as? IDef)?.run { 150 | if (name == "" && type == "") null else this 151 | } ?: first?.let { type -> 152 | (type.nextForm as? CSymbol)?.let { name -> 153 | SymKey(name.name, "", type.name) 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /src/lang/clojure-psi-index.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.psi.impl 19 | 20 | import com.intellij.util.indexing.* 21 | import com.intellij.util.io.DataExternalizer 22 | import com.intellij.util.io.EnumeratorStringDescriptor 23 | import org.intellij.clojure.lang.ClojureFileType 24 | import org.intellij.clojure.psi.CFile 25 | import org.intellij.clojure.psi.CKeyword 26 | import org.intellij.clojure.util.cljTraverser 27 | import org.intellij.clojure.util.filter 28 | import org.intellij.clojure.util.qualifiedName 29 | import java.io.DataInput 30 | import java.io.DataOutput 31 | 32 | /** 33 | * @author gregsh 34 | */ 35 | val VERSION = 204 36 | 37 | val NS_INDEX = ID.create("clojure.ns") 38 | val DEF_INDEX = ID.create("clojure.def") 39 | val DEF_FQN_INDEX = ID.create("clojure.def.fqn") 40 | val KEYWORD_INDEX = ID.create("clojure.keyword") 41 | val KEYWORD_FQN_INDEX = ID.create("clojure.keyword.fqn") 42 | 43 | class ClojureNSIndex : ClojureUnitIndex() { 44 | override fun getName(): ID = NS_INDEX 45 | override fun index(file: CFile): MutableMap { 46 | val result = mutableMapOf(file.namespace to Unit) 47 | file.defs().filter { it.def!!.type == "ns" }.forEach { 48 | result[it.def!!.name] = Unit 49 | } 50 | return result 51 | } 52 | } 53 | 54 | class ClojureDefIndex : ClojureUnitIndex() { 55 | override fun getName(): ID = DEF_INDEX 56 | override fun index(file: CFile): MutableMap { 57 | return file.defs().filter { it.def!!.type != "ns" }. map { it.def!!.name }.toMap { Unit } 58 | } 59 | } 60 | 61 | class ClojureDefFqnIndex : ClojureUnitIndex() { 62 | override fun getName(): ID = DEF_FQN_INDEX 63 | override fun index(file: CFile): MutableMap { 64 | return file.defs().filter { it.def!!.type != "ns" }.map { it.def!!.qualifiedName }.toMap { Unit } 65 | } 66 | } 67 | 68 | class ClojureKeywordIndex : ClojureUnitIndex() { 69 | override fun getName(): ID = KEYWORD_INDEX 70 | override fun index(file: CFile): MutableMap { 71 | return file.cljTraverser().traverse() 72 | .filter(CKeyword::class).map { it.name }.toMap { Unit } 73 | } 74 | } 75 | 76 | class ClojureKeywordFqnIndex : ClojureUnitIndex() { 77 | override fun getName(): ID = KEYWORD_FQN_INDEX 78 | override fun index(file: CFile): MutableMap { 79 | return file.cljTraverser().traverse() 80 | .filter(CKeyword::class).map { it.qualifiedName }.toMap { Unit } 81 | } 82 | } 83 | 84 | abstract class ClojureUnitIndex : ClojureIndexBase() { 85 | override fun readValue(input: DataInput) = Unit 86 | override fun writeValue(output: DataOutput, value: Unit) = Unit 87 | } 88 | 89 | //abstract class ClojureStringIndex : ClojureIndexBase() { 90 | // override fun readValue(input: DataInput) = IOUtil.readUTF(input) 91 | // override fun writeValue(output: DataOutput, value: String) = IOUtil.writeUTF(output, value) 92 | //} 93 | 94 | abstract class ClojureIndexBase : FileBasedIndexExtension() { 95 | override fun getVersion(): Int = VERSION 96 | override fun getKeyDescriptor(): EnumeratorStringDescriptor = EnumeratorStringDescriptor.INSTANCE 97 | override fun getInputFilter(): FileBasedIndex.InputFilter = DefaultFileTypeSpecificInputFilter (ClojureFileType) 98 | override fun dependsOnFileContent(): Boolean = true 99 | 100 | override fun getIndexer(): DataIndexer = DataIndexer { index(it.psiFile as CFile) } 101 | 102 | override fun getValueExternalizer(): DataExternalizer = object : DataExternalizer { 103 | override fun read(input: DataInput): V = readValue(input) 104 | override fun save(output: DataOutput, value: V) = writeValue(output, value) 105 | } 106 | 107 | abstract fun index(file: CFile): MutableMap 108 | abstract fun readValue(input: DataInput): V 109 | abstract fun writeValue(output: DataOutput, value: V): Unit 110 | 111 | } 112 | 113 | 114 | -------------------------------------------------------------------------------- /src/org/intellij/clojure/ui/forms/CodeStyleOtherTab.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
32 | -------------------------------------------------------------------------------- /src/org/intellij/clojure/ui/forms/CodeStyleOtherTab.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.ui.forms; 19 | 20 | import com.intellij.application.options.CodeStyleAbstractPanel; 21 | import com.intellij.lang.Language; 22 | import com.intellij.openapi.editor.colors.EditorColorsScheme; 23 | import com.intellij.openapi.editor.highlighter.EditorHighlighter; 24 | import com.intellij.openapi.fileTypes.FileType; 25 | import com.intellij.openapi.options.ConfigurationException; 26 | import com.intellij.psi.codeStyle.CodeStyleSettings; 27 | import com.intellij.ui.components.JBCheckBox; 28 | import org.intellij.clojure.lang.ClojureFileType; 29 | import org.jetbrains.annotations.NotNull; 30 | import org.jetbrains.annotations.Nullable; 31 | 32 | import javax.swing.*; 33 | 34 | import static org.intellij.clojure.formatter.Clojure_formatterKt.getClojureSettings; 35 | 36 | /** 37 | * @author gregsh 38 | */ 39 | public class CodeStyleOtherTab extends CodeStyleAbstractPanel { 40 | 41 | private JPanel myPanel; 42 | private JBCheckBox myUseDoubleSemiCb; 43 | 44 | public CodeStyleOtherTab(@Nullable Language defaultLanguage, 45 | @Nullable CodeStyleSettings currentSettings, 46 | @NotNull CodeStyleSettings settings) { 47 | super(defaultLanguage, currentSettings, settings); 48 | } 49 | 50 | @Override 51 | protected int getRightMargin() { 52 | return 0; 53 | } 54 | 55 | @Nullable 56 | @Override 57 | protected EditorHighlighter createHighlighter(EditorColorsScheme scheme) { 58 | return null; 59 | } 60 | 61 | @NotNull 62 | @Override 63 | protected FileType getFileType() { 64 | return ClojureFileType.INSTANCE; 65 | } 66 | 67 | @Nullable 68 | @Override 69 | protected String getPreviewText() { 70 | return null; 71 | } 72 | 73 | @Nullable 74 | @Override 75 | public JComponent getPanel() { 76 | return myPanel; 77 | } 78 | 79 | @Override 80 | public void apply(CodeStyleSettings settings) throws ConfigurationException { 81 | getClojureSettings(settings).USE_2SEMI_COMMENT = myUseDoubleSemiCb.isSelected(); 82 | } 83 | 84 | @Override 85 | public boolean isModified(CodeStyleSettings settings) { 86 | boolean modified = false; 87 | modified |= myUseDoubleSemiCb.isSelected() != getClojureSettings(settings).USE_2SEMI_COMMENT; 88 | return modified; 89 | } 90 | 91 | @Override 92 | protected void resetImpl(CodeStyleSettings settings) { 93 | myUseDoubleSemiCb.setSelected(getClojureSettings(settings).USE_2SEMI_COMMENT); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/tools/debugger.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.debugger 19 | 20 | import com.intellij.openapi.project.Project 21 | import com.intellij.openapi.vfs.VirtualFile 22 | import com.intellij.psi.PsiElement 23 | import com.intellij.psi.PsiFile 24 | import com.intellij.xdebugger.XSourcePosition 25 | import com.intellij.xdebugger.breakpoints.XBreakpoint 26 | import com.intellij.xdebugger.breakpoints.XBreakpointProperties 27 | import com.intellij.xdebugger.breakpoints.XLineBreakpoint 28 | import com.intellij.xdebugger.breakpoints.XLineBreakpointType 29 | import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider 30 | import com.intellij.xdebugger.evaluation.XDebuggerEditorsProviderBase 31 | import org.intellij.clojure.lang.ClojureFileType 32 | import org.intellij.clojure.lang.ClojureLanguage 33 | import org.intellij.clojure.lang.ClojureTokens 34 | import org.intellij.clojure.lang.newCodeFragment 35 | import org.intellij.clojure.util.thisForm 36 | 37 | /** 38 | * 39 | * 40 | * @author gregsh 41 | */ 42 | 43 | class ClojureLineBreakpointType : XLineBreakpointType("clojure-line", "Clojure breakpoint") { 44 | override fun createBreakpointProperties(file: VirtualFile, line: Int): ClojureBreakpointProperties { 45 | return ClojureBreakpointProperties() 46 | } 47 | 48 | override fun getSourcePosition(breakpoint: XBreakpoint): XSourcePosition? { 49 | return super.getSourcePosition(breakpoint) 50 | } 51 | 52 | override fun computeVariants(project: Project, position: XSourcePosition): MutableList { 53 | return super.computeVariants(project, position) 54 | } 55 | 56 | override fun canPutAt(file: VirtualFile, line: Int, project: Project): Boolean { 57 | return file.fileType == ClojureFileType 58 | } 59 | 60 | override fun getEditorsProvider(breakpoint: XLineBreakpoint, project: Project): XDebuggerEditorsProvider? { 61 | return object : XDebuggerEditorsProviderBase() { 62 | override fun getFileType() = ClojureFileType 63 | 64 | override fun createExpressionCodeFragment(project: Project, text: String, context: PsiElement?, isPhysical: Boolean): PsiFile { 65 | return newCodeFragment(project, ClojureLanguage, ClojureTokens.CLJ_FILE_TYPE, "eval.clj", text, context.thisForm ?: context, isPhysical) 66 | } 67 | } 68 | } 69 | } 70 | 71 | class ClojureBreakpointProperties : XBreakpointProperties() { 72 | class State 73 | 74 | private val myState: State = State() 75 | 76 | override fun getState() = myState 77 | 78 | override fun loadState(state: State) { 79 | } 80 | } 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/tools/tools.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.tools 19 | 20 | import com.intellij.execution.ExecutionException 21 | import com.intellij.execution.configurations.GeneralCommandLine 22 | import com.intellij.execution.process.OSProcessHandler 23 | import com.intellij.execution.process.ProcessAdapter 24 | import com.intellij.execution.process.ProcessEvent 25 | import com.intellij.execution.process.ProcessOutputTypes 26 | import com.intellij.notification.Notification 27 | import com.intellij.notification.NotificationType 28 | import com.intellij.notification.Notifications 29 | import com.intellij.openapi.diagnostic.Logger 30 | import com.intellij.openapi.util.Key 31 | import com.intellij.openapi.util.SystemInfo 32 | import com.intellij.openapi.util.text.StringUtil 33 | import com.intellij.openapi.vfs.CharsetToolkit 34 | import com.intellij.util.EnvironmentUtil 35 | import org.intellij.clojure.ClojureConstants 36 | import java.io.File 37 | 38 | /** 39 | * @author gregsh 40 | */ 41 | 42 | private val LOG = Logger.getInstance(Tool::class.java) 43 | const val DEPS_NOTIFICATION = "clojure-kit.tool.deps.group" 44 | 45 | object Repo { 46 | val path = File(File(com.intellij.util.SystemProperties.getUserHome(), ".m2"), "repository") 47 | } 48 | 49 | 50 | interface Tool { 51 | fun getDeps(projectFile: File): List 52 | fun getRepl(): GeneralCommandLine 53 | 54 | companion object { 55 | fun choose(file: File) = choose(file.name) 56 | fun choose(fileName: String) = when (fileName) { 57 | Lein.projectFile -> Lein 58 | Boot.projectFile -> Boot 59 | Deps.projectFile -> Deps 60 | else -> null 61 | } 62 | 63 | fun find(dir: File) = when { 64 | File(dir, Lein.projectFile).exists() -> Lein 65 | File(dir, Boot.projectFile).exists() -> Boot 66 | File(dir, Deps.projectFile).exists() -> Deps 67 | else -> null 68 | } 69 | } 70 | } 71 | 72 | object Lein : Tool { 73 | val projectFile = ClojureConstants.LEIN_CONFIG 74 | private val command = findCommandPath("lein") 75 | 76 | override fun getDeps(projectFile: File) = readProcessOutput( 77 | GeneralCommandLine(command, "deps", ":tree"), projectFile.parent) 78 | .mapNotNull(::parseCoordVector) 79 | 80 | 81 | override fun getRepl() = GeneralCommandLine(command, *mutableListOf( 82 | "update-in", ":dependencies", "conj", "[nrepl \"RELEASE\"]", "--", 83 | "update-in", ":plugins", "conj", "[cider/cider-nrepl \"RELEASE\"]", "--", 84 | "update-in", ":nrepl-middleware", "conj ", "[cider-nrepl.plugin/middleware \"RELEASE\"]", "--") 85 | .apply { 86 | val vmOpts = System.getProperty(ClojureConstants.LEIN_VM_OPTS) 87 | if (vmOpts != null) { 88 | addAll(listOf("update-in", ":jvm-opts", "into", "[\"$vmOpts\"]", "--")) 89 | } 90 | addAll(listOf("repl", ":headless")) 91 | }.toTypedArray()) 92 | } 93 | 94 | object Boot : Tool { 95 | val projectFile = ClojureConstants.BOOT_CONFIG 96 | private val command = findCommandPath("boot") 97 | 98 | override fun getDeps(projectFile: File) = readProcessOutput( 99 | GeneralCommandLine(command, "--no-colors", "show", "-d"), projectFile.parent) 100 | .mapNotNull { 101 | val trimmed = it.trimEnd() 102 | val idx = trimmed.indexOf("[") 103 | if (idx != -1 && trimmed.endsWith("]")) { 104 | val coordVec = StringUtil.repeat(" ", idx) + trimmed.substring(idx) 105 | parseCoordVector(coordVec) 106 | } 107 | else null 108 | } 109 | 110 | override fun getRepl() = GeneralCommandLine(command, 111 | "--no-colors", 112 | "-d", "nrepl", 113 | "-d", "cider/cider-nrepl", 114 | "repl", "-m", "cider.nrepl/cider-middleware", "-s", "wait") 115 | } 116 | 117 | object Deps : Tool { 118 | val projectFile = ClojureConstants.DEPS_CONFIG 119 | private val command = findCommandPath("clojure") 120 | 121 | override fun getDeps(projectFile: File) = readProcessOutput( 122 | GeneralCommandLine(command, "-Stree"), projectFile.parent) 123 | .mapNotNull { line -> 124 | Regex("(?:\\. )?(.*)/(.*) (.*)").matchEntire(line.trim())?.let { 125 | val (group, artifact, version) = it.destructured 126 | Dependency(group, artifact, version) 127 | } 128 | } 129 | 130 | override fun getRepl() = GeneralCommandLine(command, 131 | "-Sdeps", "{:deps { nrepl {:mvn/version \"RELEASE\"}" + 132 | " cider/cider-nrepl {:mvn/version \"RELEASE\"}}}", 133 | "--eval", "(do (use '[nrepl.server :only (start-server stop-server)])" + 134 | " (use '[cider.nrepl :only (cider-nrepl-handler)])" + 135 | " (println (str \"nREPL server started on port \" (:port (start-server :handler cider-nrepl-handler)) \" host localhost\")))") 136 | 137 | } 138 | 139 | 140 | private fun readProcessOutput(commandLine: GeneralCommandLine, workingDirectory: String): List { 141 | val stdout = mutableListOf() 142 | val stderr = mutableListOf() 143 | var exitCode: Int? = null 144 | val process = try { 145 | OSProcessHandler(commandLine.withWorkDirectory(workingDirectory).withCharset(CharsetToolkit.UTF8_CHARSET)) 146 | } 147 | catch (e: Exception) { 148 | val message = e.message ?: e.toString() 149 | Notifications.Bus.notify(Notification(DEPS_NOTIFICATION, "", message, NotificationType.ERROR)) 150 | throw e 151 | } 152 | process.addProcessListener(object : ProcessAdapter() { 153 | override fun onTextAvailable(event: ProcessEvent, outputType: Key<*>) { 154 | when (outputType) { 155 | ProcessOutputTypes.STDOUT -> stdout.add(event.text) 156 | ProcessOutputTypes.STDERR -> stderr.add(event.text) 157 | } 158 | } 159 | 160 | override fun processTerminated(event: ProcessEvent) { 161 | exitCode = event.exitCode 162 | } 163 | }) 164 | LOG.info("${commandLine.commandLineString} (in $workingDirectory)") 165 | process.startNotify() 166 | process.waitFor() 167 | LOG.info("${commandLine.commandLineString} (exit code: $exitCode)") 168 | if (exitCode == null || exitCode != 0) { 169 | val title = commandLine.exePath + ": exit code " + exitCode 170 | val message = if (stderr.isEmpty()) "" else stderr.joinToString("") 171 | Notifications.Bus.notify(Notification(DEPS_NOTIFICATION, title, message, NotificationType.ERROR)) 172 | throw ExecutionException(title) 173 | } 174 | return stdout 175 | } 176 | 177 | private fun findCommandPath(commandName: String): String { 178 | return (EnvironmentUtil.getValue("PATH") ?: "").split(File.pathSeparator).mapNotNull { 179 | val path = "$it${File.separator}$commandName${if (SystemInfo.isWindows) ".bat" else ""}" 180 | if (File(path).exists()) path else null 181 | }.firstOrNull() ?: commandName 182 | } 183 | -------------------------------------------------------------------------------- /src/ui/clojure-formatter-ui.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.ui.formatter 19 | 20 | import com.intellij.application.options.CodeStyleAbstractConfigurable 21 | import com.intellij.application.options.CodeStyleAbstractPanel 22 | import com.intellij.application.options.SmartIndentOptionsEditor 23 | import com.intellij.application.options.TabbedLanguageCodeStylePanel 24 | import com.intellij.lang.Language 25 | import com.intellij.psi.codeStyle.CodeStyleSettings 26 | import com.intellij.psi.codeStyle.CodeStyleSettingsProvider 27 | import com.intellij.psi.codeStyle.CommonCodeStyleSettings 28 | import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider 29 | import org.intellij.clojure.formatter.ClojureCodeStyleSettings 30 | import org.intellij.clojure.lang.ClojureLanguage 31 | import org.intellij.clojure.ui.forms.CodeStyleOtherTab 32 | 33 | /** 34 | * @author gregsh 35 | */ 36 | class ClojureCodeStyleSettingsProvider : CodeStyleSettingsProvider() { 37 | override fun getLanguage(): Language = ClojureLanguage 38 | override fun createCustomSettings(settings: CodeStyleSettings?) = ClojureCodeStyleSettings(settings) 39 | override fun createSettingsPage(settings: CodeStyleSettings, originalSettings: CodeStyleSettings) = ClojureCodeStyleConfigurable(settings, originalSettings) 40 | } 41 | 42 | class ClojureCodeStyleConfigurable(settings: CodeStyleSettings, cloneSettings: CodeStyleSettings) : CodeStyleAbstractConfigurable(settings, cloneSettings, "Clojure") { 43 | 44 | override fun createPanel(settings: CodeStyleSettings): CodeStyleAbstractPanel = Panel(currentSettings, settings) 45 | override fun getHelpTopic() = null 46 | 47 | private class Panel(currentSettings: CodeStyleSettings, settings: CodeStyleSettings) : 48 | TabbedLanguageCodeStylePanel(ClojureLanguage, currentSettings, settings) { 49 | init { 50 | addTab(CodeStyleOtherTab(ClojureLanguage, currentSettings, settings)) 51 | } 52 | } 53 | } 54 | 55 | class ClojureLangCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvider() { 56 | override fun getLanguage(): Language = ClojureLanguage 57 | override fun getIndentOptionsEditor() = SmartIndentOptionsEditor() 58 | override fun getDefaultCommonSettings() = CommonCodeStyleSettings(language).run { 59 | val indentOptions = initIndentOptions() 60 | indentOptions.INDENT_SIZE = 2 61 | indentOptions.CONTINUATION_INDENT_SIZE = 4 62 | indentOptions.TAB_SIZE = 2 63 | this 64 | } 65 | 66 | override fun getCodeSample(settingsType: SettingsType): String { 67 | return """ 68 | (ns ^{:author "wikibooks" :doc "Clojure Programming"} wikibooks.sample (:require [clojure.set :as set])) 69 | ;; Clojure Programming/Examples/Lazy Fibonacci 70 | (defn fib-seq [] ((fn rfib [a b] (cons a (lazy-seq (rfib b (+ a b))))) 0 1)) 71 | 72 | ;; Recursive Fibonacci with any start point and the amount of numbers that you want 73 | ;; note that your 'start' parameter must be a vector with at least two numbers (the two which are your starting points) 74 | (defn fib [start range] "Creates a vector of fibonnaci numbers" (if (<= range 0) start (recur (let [subvector (subvec start (- (count start) 2)) 75 | x (nth subvector 0) y (nth subvector 1) z (+ x y)] (conj start z)) (- range 1)))) 76 | """ 77 | } 78 | } -------------------------------------------------------------------------------- /testData/formatter/CodeSample.clj: -------------------------------------------------------------------------------- 1 | (ns ^{:author "wikibooks" :doc "Clojure Programming"} wikibooks.sample 2 | (:require [clojure.set :as set])) 3 | 4 | ;; Clojure Programming/Examples/Lazy Fibonacci 5 | (defn fib-seq [] ((fn rfib [a b] (cons a (lazy-seq (rfib b (+ a b))))) 0 1)) 6 | 7 | ;; Recursive Fibonacci with any start point and the amount of numbers that you want 8 | ;; note that your 'start' parameter must be a vector with at least two numbers (the two which are your starting points) 9 | (defn fib [start range] 10 | "Creates a vector of fibonnaci numbers" 11 | (if (<= range 0) 12 | start 13 | (recur 14 | (let [subvector (subvec start (- (count start) 2)) 15 | x (nth subvector 0) 16 | y (nth subvector 1) 17 | z (+ x y)] 18 | (conj start z)) 19 | (- range 1)))) 20 | -------------------------------------------------------------------------------- /testData/formatter/FormatterFixes.clj: -------------------------------------------------------------------------------- 1 | ((asdf 2 | ;; This is a comment 3 | )) 4 | 5 | ;;; reformat> 6 | ((asdf 7 | ;; This is a comment 8 | )) -------------------------------------------------------------------------------- /testData/formatter/Simple.clj: -------------------------------------------------------------------------------- 1 | {:keyword 'value, :keywordOther 'valueOther, :namespace/keyword 'value, :keywordOther 'valueOther} 2 | [:keyword 'value, :keywordOther 'valueOther, :namespace/keyword 'value, :keywordOther 'valueOther] 3 | (:form1) (:from2) 4 | 5 | ;;; reformat> println("common = $common") 6 | ;;; reformat> println("custom = $custom") 7 | 8 | {:keyword 'value, 9 | :keywordOther 'valueOther, 10 | :namespace/keyword 'value, 11 | :keywordOther 'valueOther} 12 | 13 | [:keyword 'value, 14 | :keywordOther 'valueOther, 15 | :namespace/keyword 'value, 16 | :keywordOther 'valueOther] 17 | 18 | (:form1) 19 | 20 | (:from2) -------------------------------------------------------------------------------- /testData/formatter/StyleGuide.clj: -------------------------------------------------------------------------------- 1 | ;; good 2 | (when something 3 | (something-else)) 4 | 5 | (with-out-str 6 | (println "Hello, ") 7 | (println "world!")) 8 | 9 | ;; bad - four spaces 10 | (when something 11 | (something-else)) 12 | 13 | ;; bad 14 | (let [] 15 | (when something 16 | (something-else))) 17 | 18 | ;; bad - one space 19 | (with-out-str 20 | (println "Hello, ") 21 | (println "world!")) 22 | 23 | ;; good 24 | (filter even? 25 | (range 1 10)) 26 | 27 | ;; bad 28 | (filter even? 29 | (range 1 10)) 30 | 31 | ;; good 32 | (filter 33 | even? 34 | (range 1 10)) 35 | 36 | (or 37 | ala 38 | bala 39 | portokala) 40 | 41 | ;; bad - two-space indent 42 | (filter 43 | even? 44 | (range 1 10)) 45 | 46 | (or 47 | ala 48 | bala 49 | portokala) 50 | 51 | ;; good 52 | (let [thing1 "some stuff" 53 | thing2 "other stuff"] 54 | {:thing1 thing1 55 | :thing2 thing2}) 56 | 57 | ;; bad 58 | (let [thing1 "some stuff" 59 | thing2 "other stuff"] 60 | {:thing1 thing1 61 | :thing2 thing2}) 62 | 63 | ;; good 64 | (defn foo 65 | [x] 66 | (bar x)) 67 | 68 | ;; good 69 | (defn foo [x] 70 | (bar x)) 71 | 72 | ;; bad 73 | (defn foo 74 | [x] (bar x)) 75 | 76 | ;; good 77 | (defmethod foo :bar [x] (baz x)) 78 | 79 | (defmethod foo :bar 80 | [x] 81 | (baz x)) 82 | 83 | ;; bad 84 | (defmethod foo 85 | :bar 86 | [x] 87 | (baz x)) 88 | 89 | (defmethod foo 90 | :bar [x] 91 | (baz x)) 92 | 93 | ;; good 94 | (defn foo [x] 95 | (bar x)) 96 | 97 | ;; good for a small function body 98 | (defn foo [x] (bar x)) 99 | 100 | ;; good for multi-arity functions 101 | (defn foo 102 | ([x] (bar x)) 103 | ([x y] 104 | (if (predicate? x) 105 | (bar x) 106 | (baz x)))) 107 | 108 | ;; bad 109 | (defn foo 110 | [x] (if (predicate? x) 111 | (bar x) 112 | (baz x))) 113 | 114 | ;; bad 115 | (defn foo [x] (if (predicate? x) 116 | (bar x) 117 | (baz x))) 118 | 119 | ;; good 120 | (defn foo 121 | "I have two arities." 122 | ([x] 123 | (foo x 1)) 124 | ([x y] 125 | (+ x y))) 126 | 127 | ;; bad - extra indentation 128 | (defn foo 129 | "I have two arities." 130 | ([x] 131 | (foo x 1)) 132 | ([x y] 133 | (+ x y))) 134 | 135 | ;; good 136 | (foo (bar baz) quux) 137 | 138 | ;; bad 139 | (foo(bar baz)quux) 140 | (foo ( bar baz ) quux) 141 | 142 | ;; good; single line 143 | (when something 144 | (something-else)) 145 | 146 | ;; bad; distinct lines 147 | (when something 148 | (something-else) 149 | ) 150 | 151 | ;; good 152 | (def min-rows 10) 153 | (def max-rows 20) 154 | (def min-cols 15) 155 | (def max-cols 30) 156 | 157 | (defn foo ...) 158 | 159 | ;; bad 160 | (def x ...) 161 | (defn foo ...) 162 | 163 | 164 | ;;; reformat> 165 | ;;; reformat> 166 | 167 | ;; good 168 | (when something 169 | (something-else)) 170 | 171 | (with-out-str 172 | (println "Hello, ") 173 | (println "world!")) 174 | 175 | ;; bad - four spaces 176 | (when something 177 | (something-else)) 178 | 179 | ;; bad 180 | (let [] 181 | (when something 182 | (something-else))) 183 | 184 | ;; bad - one space 185 | (with-out-str 186 | (println "Hello, ") 187 | (println "world!")) 188 | 189 | ;; good 190 | (filter even? 191 | (range 1 10)) 192 | 193 | ;; bad 194 | (filter even? 195 | (range 1 10)) 196 | 197 | ;; good 198 | (filter 199 | even? 200 | (range 1 10)) 201 | 202 | (or 203 | ala 204 | bala 205 | portokala) 206 | 207 | ;; bad - two-space indent 208 | (filter 209 | even? 210 | (range 1 10)) 211 | 212 | (or 213 | ala 214 | bala 215 | portokala) 216 | 217 | ;; good 218 | (let [thing1 "some stuff" 219 | thing2 "other stuff"] 220 | {:thing1 thing1 221 | :thing2 thing2}) 222 | 223 | ;; bad 224 | (let [thing1 "some stuff" 225 | thing2 "other stuff"] 226 | {:thing1 thing1 227 | :thing2 thing2}) 228 | 229 | ;; good 230 | (defn foo 231 | [x] 232 | (bar x)) 233 | 234 | ;; good 235 | (defn foo [x] 236 | (bar x)) 237 | 238 | ;; bad 239 | (defn foo 240 | [x] 241 | (bar x)) 242 | 243 | ;; good 244 | (defmethod foo :bar [x] (baz x)) 245 | 246 | (defmethod foo :bar 247 | [x] 248 | (baz x)) 249 | 250 | ;; bad 251 | (defmethod foo :bar 252 | [x] 253 | (baz x)) 254 | 255 | (defmethod foo :bar 256 | [x] 257 | (baz x)) 258 | 259 | ;; good 260 | (defn foo [x] 261 | (bar x)) 262 | 263 | ;; good for a small function body 264 | (defn foo [x] (bar x)) 265 | 266 | ;; good for multi-arity functions 267 | (defn foo 268 | ([x] (bar x)) 269 | ([x y] 270 | (if (predicate? x) 271 | (bar x) 272 | (baz x)))) 273 | 274 | ;; bad 275 | (defn foo 276 | [x] 277 | (if (predicate? x) 278 | (bar x) 279 | (baz x))) 280 | 281 | ;; bad 282 | (defn foo [x] 283 | (if (predicate? x) 284 | (bar x) 285 | (baz x))) 286 | 287 | ;; good 288 | (defn foo 289 | "I have two arities." 290 | ([x] 291 | (foo x 1)) 292 | ([x y] 293 | (+ x y))) 294 | 295 | ;; bad - extra indentation 296 | (defn foo 297 | "I have two arities." 298 | ([x] 299 | (foo x 1)) 300 | ([x y] 301 | (+ x y))) 302 | 303 | ;; good 304 | (foo (bar baz) quux) 305 | 306 | ;; bad 307 | (foo (bar baz) quux) 308 | (foo (bar baz) quux) 309 | 310 | ;; good; single line 311 | (when something 312 | (something-else)) 313 | 314 | ;; bad; distinct lines 315 | (when something 316 | (something-else)) 317 | 318 | ;; good 319 | (def min-rows 10) 320 | (def max-rows 20) 321 | (def min-cols 15) 322 | (def max-cols 30) 323 | 324 | (defn foo ...) 325 | 326 | ;; bad 327 | (def x ...) 328 | 329 | (defn foo ...) -------------------------------------------------------------------------------- /testData/highlighting/ClojureFixes.clj: -------------------------------------------------------------------------------- 1 | ;; imports 2 | (do 3 | (refer 'clojure.set) 4 | (union) 5 | (intersection #{1} #{1 2}) 6 | ) 7 | (do 8 | (refer 'clojure.set :as s3 :exclude '[intersection]) 9 | (union) 10 | (intersection #{1} #{1 2}) 11 | (s3/union) 12 | ) 13 | (do 14 | (refer 'clojure.set :rename {union union_renamed}) 15 | (union_renamed) 16 | (union) 17 | ) 18 | 19 | (do 20 | (require 'clojure.set :as s1) 21 | (union) 22 | (s1/union) 23 | (require '[clojure.set :as s1]) 24 | (union) 25 | (s1/union) 26 | ) 27 | (do 28 | (require '[clojure [set :as s1] [data :as s2]]) 29 | (union) 30 | (s1/union) 31 | ) 32 | (do 33 | (require '(clojure zip [set :as s2])) 34 | (union) 35 | (s1/union) 36 | (s2/union) 37 | ) 38 | (do 39 | (require '(clojure zip [set :refer :all])) 40 | (union) 41 | (intersection #{1} #{1 2}) 42 | ) 43 | (do 44 | (require '[clojure.string :refer [blank?]]) 45 | (blank?) 46 | (trim-newline) 47 | (when-let [nsname 'foo.core'] 48 | (require (symbol nsname))) 49 | ) 50 | (do 51 | (ns nsns (:require [clojure.core])) 52 | (require '[clojure.missing])) 53 | 54 | (do 55 | (use '[clojure.set :as s1]) 56 | (union) 57 | (s1/union) 58 | ) 59 | (do 60 | (use '(clojure zip [set :as s2])) 61 | (union) 62 | (s2/union) 63 | ) 64 | (do 65 | (use '(clojure zip [set :refer [union] :only [union]])) 66 | (union) 67 | (intersection #{1} #{1 2}) 68 | ) 69 | 70 | (do 71 | (no-forward-def) 72 | (defn no-forward-def [] (no-forward-def)) 73 | (no-forward-def) 74 | ) 75 | (do 76 | (defmacro some-macro) 77 | (some-macro allow-forward-decl-in-spec) 78 | (defn allow-forward-decl-in-spec) 79 | ) 80 | (do 81 | (alias 'clojure.set-alias 'clojure.set) 82 | (defn no-resolve-to-alias [] [clojure.set-alias clojure.set-alias/union]) 83 | ) 84 | 85 | @not-to-resolve 86 | #:some-ns {:some-key not-to-resolve} 87 | (#'clojure.uuid/default-uuid-reader) 88 | (clojure.uuid/default-uuid-reader) 89 | 90 | (def #_comment named-zero 0) 91 | {#_0 #_1 :a #_'(xxx) 'a :b #_:comm 'b #_2 #_3} 92 | # #_comment dbg 10 93 | 94 | ::missing_alias/kwd 95 | 96 | ' ^meta #_ comment quoted_sym 97 | 98 | (do 99 | (deftype Type [x y]) 100 | (.equals (->Type 1 2) (map->Type {:x 1 :y 2})) 101 | (.-x (->Type 1 2)) 102 | 103 | (defrecord Record [x y]) 104 | (.equals (user/->Record 1 2) (map->Record {:x 1 :y 2})) 105 | (. (map->Record {:x 1 :y 2}) -x) 106 | ) 107 | 108 | (defn keys-destr [{:keys [clojure.core/abc missing_ns/edf ijk] 109 | :or {abc 1, edf 2, ijk 3, missing_key 4}}] 110 | (print abc edf ijk)) 111 | 112 | (do 113 | (defprotocol Named (name [this])) 114 | (extend-protocol Named 115 | java.lang.Class 116 | (name [c] ((. c getName)))) 117 | (extend Runnable 118 | Named 119 | {:name (fn [c] (.run c))}) 120 | 121 | (import [java.io Writer]) 122 | (proxy [Writer Runnable] [] 123 | (close [] (do (.run this) (.flush this)))) 124 | (reify 125 | Writer 126 | (close [] (do (.run this) (.flush this))) 127 | Runnable 128 | (run []) 129 | )) 130 | 131 | (do 132 | (.. Integer (parseInt "12") floatValue) 133 | 134 | (.. (Object.) getClass isArray) 135 | 136 | (doto (Object.) (.getClass) (.getClass)) 137 | (doto (Object.) .getClass .getClass) 138 | 139 | (-> (Object.) (.getClass) (.getName)) 140 | (-> (Object.) .getClass .getName)) 141 | 142 | (do 143 | (alias bar clojure.set) 144 | (alias 'buz 'clojure.set) 145 | (alias 'bar.buz 'clojure.core) 146 | (buz/union)) -------------------------------------------------------------------------------- /testData/highlighting/samples.clj: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ; destructuring 3 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4 | 5 | 6 | (let [[a b c & d :as e] [1 2 3 4 5 6 7]] 7 | [a b c d e]) 8 | 9 | ;->[1 2 3 (4 5 6 7) [1 2 3 4 5 6 7]] 10 | 11 | 12 | (let [[[x1 y1][x2 y2]] [[1 2] [3 4]]] 13 | [x1 y1 x2 y2]) 14 | 15 | ;->[1 2 3 4] 16 | 17 | (let [[a b & c :as str] "asdjhhfdas"] 18 | [a b c str]) 19 | 20 | ;->[\a \s (\d \j \h \h \f \d \a \s) "asdjhhfdas"] 21 | 22 | (let [{a :a, b :b, c :c, :as m :or {a 2 b 3}} {:a 5 :c 6}] 23 | [a b c m]) 24 | 25 | ;->[5 3 6 {:c 6, :a 5}] 26 | 27 | (let [m {:x/a 1, :y/b 2} 28 | {:keys [x/a y/b]} m] 29 | (+ a b)) 30 | 31 | ;-> 3 32 | 33 | (let [m {::x 42} 34 | {:keys [::x]} m] 35 | x ) 36 | 37 | ;-> 42 38 | 39 | (let [{j :j, k :k, i :i, [r s & t :as v] :ivec, :or {i 12 j 13}} 40 | {:j 15 :k 16 :ivec [22 23 24 25]}] 41 | [i j k r s t v]) 42 | 43 | ;-> [12 15 16 22 23 (24 25) [22 23 24 25]] 44 | 45 | ; clojure 1.9 46 | (let [m #:domain{:a 1, :b 2} 47 | {:domain/keys [a b]} m] 48 | [a b]) 49 | 50 | ;-> [1 2] -------------------------------------------------------------------------------- /testData/lexer/DispatchAndQuote.txt: -------------------------------------------------------------------------------- 1 | # ('#') 2 | { ('{') 3 | } ('}') 4 | WHITE_SPACE (' ') 5 | # ('#') 6 | string ('"\s*\d+"') 7 | WHITE_SPACE (' ') 8 | #' ('#'') 9 | sym ('x') 10 | WHITE_SPACE (' ') 11 | # ('#') 12 | ( ('(') 13 | WHITE_SPACE (' ') 14 | ) (')') 15 | WHITE_SPACE (' ') 16 | #_ ('#_') 17 | WHITE_SPACE ('\n') 18 | ' (''') 19 | sym ('quote') 20 | WHITE_SPACE (' ') 21 | ` ('`') 22 | sym ('qualify') 23 | WHITE_SPACE (' ') 24 | ~ ('~') 25 | sym ('unquote') 26 | WHITE_SPACE (' ') 27 | ~@ ('~@') 28 | sym ('unquote-splicing') 29 | WHITE_SPACE ('\n') 30 | #? ('#?') 31 | ( ('(') 32 | : (':') 33 | sym ('clj') 34 | WHITE_SPACE (' ') 35 | sym ('Double') 36 | / ('/') 37 | sym ('NaN') 38 | WHITE_SPACE (' ') 39 | : (':') 40 | sym ('cljs') 41 | WHITE_SPACE (' ') 42 | sym ('js') 43 | / ('/') 44 | sym ('NaN') 45 | WHITE_SPACE (' ') 46 | : (':') 47 | sym ('default') 48 | WHITE_SPACE (' ') 49 | nil ('nil') 50 | ) (')') 51 | WHITE_SPACE ('\n') 52 | #?@ ('#?@') 53 | ( ('(') 54 | : (':') 55 | sym ('clj') 56 | WHITE_SPACE (' ') 57 | [ ('[') 58 | number ('3') 59 | WHITE_SPACE (' ') 60 | number ('4') 61 | ] (']') 62 | WHITE_SPACE (' ') 63 | : (':') 64 | sym ('cljs') 65 | WHITE_SPACE (' ') 66 | [ ('[') 67 | number ('5') 68 | WHITE_SPACE (' ') 69 | number ('6') 70 | ] (']') 71 | ) (')') -------------------------------------------------------------------------------- /testData/lexer/HighlightForm.txt: -------------------------------------------------------------------------------- 1 | ( ('(') 2 | C_CALLABLE* ('abc') 3 | WHITE_SPACE (' ') 4 | : (':') 5 | C_KEYWORD* ('kwd') 6 | WHITE_SPACE (' ') 7 | ' (''') 8 | ( ('(') 9 | sym ('quoted') 10 | WHITE_SPACE (' ') 11 | sym ('xyz') 12 | ) (')') 13 | WHITE_SPACE (' ') 14 | ( ('(') 15 | C_CALLABLE* ('some.ns') 16 | C_CALLABLE* ('/') 17 | C_CALLABLE* ('fn') 18 | WHITE_SPACE (' ') 19 | : (':') 20 | C_KEYWORD* ('some.ns') 21 | C_KEYWORD* ('/') 22 | C_KEYWORD* ('kwd') 23 | WHITE_SPACE (' ') 24 | :: ('::') 25 | C_KEYWORD* ('user-kwd') 26 | WHITE_SPACE (' ') 27 | ( ('(') 28 | .- ('.-') 29 | C_CALLABLE* ('x') 30 | WHITE_SPACE (' ') 31 | ( ('(') 32 | . ('.') 33 | C_CALLABLE* ('y') 34 | WHITE_SPACE (' ') 35 | sym ('z') 36 | ) (')') 37 | ) (')') 38 | ) (')') 39 | WHITE_SPACE (' ') 40 | #_ ('#_') 41 | ( ('(') 42 | C_CALLABLE* ('comment') 43 | WHITE_SPACE (' ') 44 | ) (')') -------------------------------------------------------------------------------- /testData/lexer/HighlightSingleSharp.txt: -------------------------------------------------------------------------------- 1 | BAD_CHARACTER ('#') -------------------------------------------------------------------------------- /testData/lexer/Literals.txt: -------------------------------------------------------------------------------- 1 | string ('"a"') 2 | WHITE_SPACE (' ') 3 | string ('"\""') 4 | WHITE_SPACE (' ') 5 | string ('"\\\\\""') 6 | WHITE_SPACE (' ') 7 | string ('"new\nline"') 8 | WHITE_SPACE ('\n') 9 | number ('42') 10 | WHITE_SPACE (' ') 11 | number ('-2') 12 | WHITE_SPACE (' ') 13 | hexnum ('0x12') 14 | WHITE_SPACE (' ') 15 | number ('42N') 16 | WHITE_SPACE (' ') 17 | hexnum ('0x12N') 18 | WHITE_SPACE (' ') 19 | number ('23M') 20 | WHITE_SPACE (' ') 21 | number ('023N') 22 | WHITE_SPACE (' ') 23 | number ('023M') 24 | WHITE_SPACE ('\n') 25 | rdxnum ('2r101010') 26 | , (',') 27 | WHITE_SPACE (' ') 28 | rdxnum ('8r52') 29 | , (',') 30 | WHITE_SPACE (' ') 31 | rdxnum ('36r16') 32 | , (',') 33 | WHITE_SPACE ('\n') 34 | ratio ('-2/3') 35 | WHITE_SPACE ('\n') 36 | number ('+2.2') 37 | WHITE_SPACE (' ') 38 | number ('23.4') 39 | WHITE_SPACE (' ') 40 | number ('34.') 41 | WHITE_SPACE (' ') 42 | number ('34.e2') 43 | WHITE_SPACE (' ') 44 | number ('2e3') 45 | WHITE_SPACE (' ') 46 | number ('2e+3') 47 | WHITE_SPACE (' ') 48 | number ('2e-4') 49 | WHITE_SPACE (' ') 50 | number ('2.0e3') 51 | WHITE_SPACE (' ') 52 | number ('3.3e-3M') 53 | WHITE_SPACE (' ') 54 | number ('99.99M') 55 | WHITE_SPACE ('\n') 56 | ratio ('22/7') 57 | WHITE_SPACE ('\n') 58 | char ('\c') 59 | , (',') 60 | WHITE_SPACE (' ') 61 | char ('\newline') 62 | , (',') 63 | WHITE_SPACE (' ') 64 | char ('\space') 65 | , (',') 66 | WHITE_SPACE (' ') 67 | char ('\tab') 68 | , (',') 69 | WHITE_SPACE (' ') 70 | char ('\formfeed') 71 | , (',') 72 | WHITE_SPACE (' ') 73 | char ('\backspace') 74 | , (',') 75 | WHITE_SPACE (' ') 76 | sym ('and') 77 | WHITE_SPACE (' ') 78 | char ('\return') 79 | WHITE_SPACE ('\n') 80 | char ('\u89AF') 81 | WHITE_SPACE (' ') 82 | char ('\u03A9') 83 | WHITE_SPACE (' ') 84 | char ('\o677') 85 | WHITE_SPACE ('\n') 86 | nil ('nil') 87 | WHITE_SPACE (' ') 88 | bool ('true') 89 | WHITE_SPACE (' ') 90 | bool ('false') 91 | WHITE_SPACE ('\n\n') 92 | BAD_CHARACTER ('2.2N') 93 | WHITE_SPACE (' ') 94 | BAD_CHARACTER ('+0x23M') 95 | WHITE_SPACE (' ') 96 | BAD_CHARACTER ('023abc') 97 | WHITE_SPACE (' ') 98 | BAD_CHARACTER ('\uTRYY') 99 | WHITE_SPACE (' ') 100 | BAD_CHARACTER ('\uFFFFuuu') 101 | WHITE_SPACE (' ') 102 | BAD_CHARACTER ('\o1234') 103 | WHITE_SPACE ('\n\n') 104 | sym ('a') 105 | string ('""') 106 | sym ('+') 107 | WHITE_SPACE (' ') 108 | string ('""') 109 | sym ('a+') 110 | WHITE_SPACE (' ') 111 | string ('""') 112 | sym ('+a') 113 | WHITE_SPACE (' ') 114 | sym ('+') 115 | string ('""') 116 | sym ('a') 117 | WHITE_SPACE (' \n') 118 | number ('1') 119 | char ('\b') 120 | WHITE_SPACE ('\n') 121 | BAD_CHARACTER ('1true') 122 | WHITE_SPACE (' ') 123 | BAD_CHARACTER ('1+') 124 | WHITE_SPACE ('\n\n') 125 | BAD_CHARACTER ('"unclosed') -------------------------------------------------------------------------------- /testData/lexer/SymbolsAndKeywords.txt: -------------------------------------------------------------------------------- 1 | sym ('a') 2 | WHITE_SPACE (' ') 3 | : (':') 4 | sym ('a') 5 | WHITE_SPACE (' ') 6 | :: ('::') 7 | sym ('a') 8 | WHITE_SPACE (' ') 9 | : (':') 10 | sym ('a') 11 | BAD_CHARACTER (':') 12 | WHITE_SPACE (' ') 13 | : (':') 14 | sym ('a:a') 15 | WHITE_SPACE (' ') 16 | :: ('::') 17 | sym ('a:a') 18 | WHITE_SPACE (' ') 19 | : (':') 20 | sym ('a:a') 21 | BAD_CHARACTER (':') 22 | WHITE_SPACE ('\n') 23 | sym ('$') 24 | WHITE_SPACE (' ') 25 | sym ('%') 26 | WHITE_SPACE (' ') 27 | sym ('&') 28 | WHITE_SPACE (' ') 29 | # ('#') 30 | WHITE_SPACE (' ') 31 | sym ('%2') 32 | WHITE_SPACE (' ') 33 | sym ('a&') 34 | WHITE_SPACE (' ') 35 | sym ('-a') 36 | WHITE_SPACE (' ') 37 | sym ('+a') 38 | WHITE_SPACE (' ') 39 | sym ('*a*') 40 | WHITE_SPACE (' ') 41 | sym ('a#') 42 | WHITE_SPACE ('\n') 43 | sym ('a.b') 44 | WHITE_SPACE (' ') 45 | : (':') 46 | sym ('a.b') 47 | WHITE_SPACE (' ') 48 | sym ('a') 49 | / ('/') 50 | sym ('b') 51 | WHITE_SPACE (' ') 52 | : (':') 53 | sym ('a') 54 | / ('/') 55 | sym ('b') 56 | WHITE_SPACE (' ') 57 | :: ('::') 58 | sym ('a') 59 | / ('/') 60 | sym ('b') 61 | WHITE_SPACE (' ') 62 | sym ('a.b') 63 | / ('/') 64 | sym ('c') 65 | WHITE_SPACE (' ') 66 | : (':') 67 | sym ('a.b') 68 | / ('/') 69 | sym ('c') 70 | WHITE_SPACE (' ') 71 | :: ('::') 72 | sym ('a.b') 73 | / ('/') 74 | sym ('c') 75 | WHITE_SPACE ('\n') 76 | ' (''') 77 | sym ('a'b') 78 | WHITE_SPACE (' ') 79 | ' (''') 80 | sym ('.') 81 | WHITE_SPACE (' ') 82 | ' (''') 83 | sym ('/') 84 | WHITE_SPACE (' ') 85 | sym ('a'''') 86 | WHITE_SPACE (' ') 87 | sym ('/') 88 | WHITE_SPACE (' ') 89 | ( ('(') 90 | ' (''') 91 | sym ('/') 92 | ) (')') 93 | WHITE_SPACE (' ') 94 | sym ('a') 95 | / ('/') 96 | sym ('/') 97 | WHITE_SPACE (' ') 98 | BAD_CHARACTER ('/a') 99 | WHITE_SPACE (' ') 100 | sym ('a') 101 | / ('/') 102 | WHITE_SPACE (' ') 103 | sym ('a') 104 | / ('/') 105 | sym ('b') 106 | BAD_CHARACTER ('/c') 107 | WHITE_SPACE ('\n') 108 | : (':') 109 | sym ('fred') 110 | WHITE_SPACE (' ') 111 | : (':') 112 | sym ('person') 113 | / ('/') 114 | sym ('name') 115 | WHITE_SPACE (' ') 116 | :: ('::') 117 | sym ('rect') 118 | WHITE_SPACE ('\n') 119 | : (':') 120 | sym ('1') 121 | WHITE_SPACE (' ') 122 | : (':') 123 | sym ('-') 124 | WHITE_SPACE (' ') 125 | : (':') 126 | sym ('*') 127 | WHITE_SPACE (' ') 128 | : (':') 129 | sym ('|') 130 | WHITE_SPACE (' ') 131 | : (':') 132 | sym ('&') 133 | WHITE_SPACE (' ') 134 | . ('.') 135 | sym ('1') 136 | WHITE_SPACE (' ') 137 | sym ('a|b') 138 | WHITE_SPACE ('\n') 139 | sym ('.') 140 | WHITE_SPACE (' ') 141 | . ('.') 142 | sym ('a') 143 | WHITE_SPACE (' ') 144 | sym ('a') 145 | . ('.') 146 | WHITE_SPACE (' ') 147 | sym ('a.b') 148 | WHITE_SPACE (' ') 149 | sym ('a') 150 | / ('/') 151 | sym ('b') 152 | . ('.') 153 | WHITE_SPACE (' ') 154 | sym ('a.b') 155 | / ('/') 156 | sym ('c') 157 | . ('.') 158 | WHITE_SPACE ('\n') 159 | sym ('.-') 160 | WHITE_SPACE (' ') 161 | sym ('-a') 162 | WHITE_SPACE ('\n') 163 | sym ('-') 164 | . ('.') 165 | WHITE_SPACE (' ') 166 | sym ('a-') 167 | WHITE_SPACE (' ') 168 | sym ('a-b') 169 | WHITE_SPACE (' ') 170 | . ('.') 171 | sym ('a') 172 | / ('/') 173 | sym ('c') 174 | WHITE_SPACE (' ') 175 | . ('.') 176 | sym ('a.b') 177 | / ('/') 178 | sym ('c') 179 | WHITE_SPACE ('\n') 180 | sym ('..') 181 | WHITE_SPACE (' ') 182 | sym ('..a') 183 | WHITE_SPACE (' ') 184 | sym ('a..') 185 | WHITE_SPACE (' ') 186 | sym ('..a') 187 | / ('/') 188 | sym ('b') 189 | WHITE_SPACE (' ') 190 | sym ('a..b') -------------------------------------------------------------------------------- /testData/parser/CommentedForms.txt: -------------------------------------------------------------------------------- 1 | CFileImpl:a.clj 2 | CListImpl(C_LIST) 3 | PsiElement(()('(') 4 | CSymbolImpl(C_SYMBOL) 5 | PsiElement(sym)('def') 6 | PsiWhiteSpace(' ') 7 | CSymbolImpl(C_SYMBOL) 8 | CMetadataImpl(C_METADATA) 9 | PsiElement(^)('^') 10 | CSymbolImpl(C_SYMBOL) 11 | PsiElement(sym)('int') 12 | PsiWhiteSpace(' ') 13 | PsiElement(C_COMMENTED) 14 | PsiElement(#_)('#_') 15 | CSymbolImpl(C_SYMBOL) 16 | PsiElement(sym)('cc') 17 | PsiWhiteSpace(' ') 18 | PsiElement(sym)('n') 19 | PsiWhiteSpace(' ') 20 | CLiteralImpl(C_LITERAL) 21 | PsiElement(number)('0') 22 | PsiElement())(')') 23 | PsiWhiteSpace(' ') 24 | CMapImpl(C_MAP) 25 | PsiElement({)('{') 26 | PsiElement(C_COMMENTED) 27 | PsiElement(#_)('#_') 28 | CLiteralImpl(C_LITERAL) 29 | PsiElement(number)('0') 30 | PsiWhiteSpace(' ') 31 | PsiElement(C_COMMENTED) 32 | PsiElement(#_)('#_') 33 | CLiteralImpl(C_LITERAL) 34 | PsiElement(number)('1') 35 | PsiWhiteSpace(' ') 36 | CKeywordImpl(C_KEYWORD) 37 | PsiElement(:)(':') 38 | CSymbolImpl(C_SYMBOL) 39 | PsiElement(sym)('a') 40 | PsiWhiteSpace(' ') 41 | CSymbolImpl(C_SYMBOL) 42 | CReaderMacroImpl(C_READER_MACRO) 43 | PsiElement(')(''') 44 | PsiElement(C_COMMENTED) 45 | PsiElement(#_)('#_') 46 | CListImpl(C_LIST) 47 | CReaderMacroImpl(C_READER_MACRO) 48 | PsiElement(')(''') 49 | PsiElement(()('(') 50 | CSymbolImpl(C_SYMBOL) 51 | PsiElement(sym)('xxx') 52 | PsiElement())(')') 53 | PsiWhiteSpace(' ') 54 | PsiElement(sym)('a') 55 | PsiWhiteSpace(' ') 56 | CKeywordImpl(C_KEYWORD) 57 | PsiElement(:)(':') 58 | CSymbolImpl(C_SYMBOL) 59 | PsiElement(sym)('b') 60 | PsiWhiteSpace(' ') 61 | CSymbolImpl(C_SYMBOL) 62 | CReaderMacroImpl(C_READER_MACRO) 63 | PsiElement(')(''') 64 | PsiElement(sym)('b') 65 | PsiWhiteSpace(' ') 66 | PsiElement(C_COMMENTED) 67 | PsiElement(#_)('#_') 68 | CLiteralImpl(C_LITERAL) 69 | PsiElement(number)('2') 70 | PsiWhiteSpace(' ') 71 | PsiElement(C_COMMENTED) 72 | PsiElement(#_)('#_') 73 | CLiteralImpl(C_LITERAL) 74 | PsiElement(number)('3') 75 | PsiElement(})('}') 76 | PsiWhiteSpace(' ') 77 | CConstructorImpl(C_CONSTRUCTOR) 78 | PsiElement(#)('#') 79 | PsiWhiteSpace(' ') 80 | PsiElement(C_COMMENTED) 81 | PsiElement(#_)('#_') 82 | CSymbolImpl(C_SYMBOL) 83 | PsiElement(sym)('asd') 84 | PsiWhiteSpace(' ') 85 | CSymbolImpl(C_SYMBOL) 86 | PsiElement(sym)('dbg') 87 | PsiWhiteSpace(' ') 88 | CLiteralImpl(C_LITERAL) 89 | PsiElement(number)('10') -------------------------------------------------------------------------------- /testData/parser/FirstAndSimple.txt: -------------------------------------------------------------------------------- 1 | CFileImpl:a.clj 2 | PsiComment(C_LINE_COMMENT)(';line') 3 | PsiWhiteSpace('\n') 4 | CListImpl(C_LIST) 5 | PsiElement(()('(') 6 | CSymbolImpl(C_SYMBOL) 7 | PsiElement(sym)('+') 8 | PsiWhiteSpace(' ') 9 | CLiteralImpl(C_LITERAL) 10 | PsiElement(number)('1') 11 | PsiWhiteSpace(' ') 12 | CLiteralImpl(C_LITERAL) 13 | PsiElement(number)('2') 14 | PsiWhiteSpace(' ') 15 | CLiteralImpl(C_LITERAL) 16 | PsiElement(number)('3') 17 | PsiElement())(')') 18 | PsiWhiteSpace('\n') 19 | CListImpl(C_LIST) 20 | PsiElement(()('(') 21 | CSymbolImpl(C_SYMBOL) 22 | CSymbolImpl(C_SYMBOL) 23 | PsiElement(sym)('clojure.core') 24 | PsiElement(/)('/') 25 | PsiElement(sym)('str') 26 | PsiWhiteSpace(' ') 27 | CLiteralImpl(C_LITERAL) 28 | PsiElement(string)('"a"') 29 | PsiWhiteSpace(' ') 30 | CSymbolImpl(C_SYMBOL) 31 | CReaderMacroImpl(C_READER_MACRO) 32 | PsiElement(')(''') 33 | PsiElement(sym)('..') 34 | PsiWhiteSpace(' ') 35 | CAccessImpl(C_ACCESS) 36 | CReaderMacroImpl(C_READER_MACRO) 37 | PsiElement(')(''') 38 | PsiElement(.-)('.-') 39 | CSymbolImpl(C_SYMBOL) 40 | PsiElement(sym)('a') 41 | PsiWhiteSpace(' ') 42 | CSymbolImpl(C_SYMBOL) 43 | PsiElement(sym)('val') 44 | PsiWhiteSpace(' ') 45 | CLiteralImpl(C_LITERAL) 46 | PsiElement(number)('123') 47 | PsiWhiteSpace(' ') 48 | CKeywordImpl(C_KEYWORD) 49 | PsiElement(:)(':') 50 | CSymbolImpl(C_SYMBOL) 51 | PsiElement(sym)('key') 52 | PsiElement())(')') -------------------------------------------------------------------------------- /testData/parser/InterOp.txt: -------------------------------------------------------------------------------- 1 | CFileImpl:a.clj 2 | CListImpl(C_LIST) 3 | PsiElement(()('(') 4 | CAccessImpl(C_ACCESS) 5 | CSymbolImpl(C_SYMBOL) 6 | PsiElement(sym)('a') 7 | PsiElement(.)('.') 8 | PsiElement())(')') 9 | PsiWhiteSpace(' ') 10 | CListImpl(C_LIST) 11 | PsiElement(()('(') 12 | CAccessImpl(C_ACCESS) 13 | CSymbolImpl(C_SYMBOL) 14 | CSymbolImpl(C_SYMBOL) 15 | PsiElement(sym)('a') 16 | PsiElement(/)('/') 17 | PsiElement(sym)('b') 18 | PsiElement(.)('.') 19 | PsiElement())(')') -------------------------------------------------------------------------------- /testData/parser/MapPrefix.txt: -------------------------------------------------------------------------------- 1 | CFileImpl:a.clj 2 | CMapImpl(C_MAP) 3 | CReaderMacroImpl(C_READER_MACRO) 4 | PsiElement(#:)('#') 5 | PsiElement(:)(':') 6 | CSymbolImpl(C_SYMBOL) 7 | PsiElement(sym)('asd') 8 | PsiElement({)('{') 9 | CKeywordImpl(C_KEYWORD) 10 | PsiElement(:)(':') 11 | CSymbolImpl(C_SYMBOL) 12 | PsiElement(sym)('a') 13 | PsiWhiteSpace(' ') 14 | CLiteralImpl(C_LITERAL) 15 | PsiElement(number)('1') 16 | PsiWhiteSpace(' ') 17 | CKeywordImpl(C_KEYWORD) 18 | PsiElement(:)(':') 19 | CSymbolImpl(C_SYMBOL) 20 | PsiElement(sym)('b') 21 | PsiWhiteSpace(' ') 22 | CMapImpl(C_MAP) 23 | CReaderMacroImpl(C_READER_MACRO) 24 | PsiElement(#:)('#') 25 | PsiElement(::)('::') 26 | PsiElement({)('{') 27 | CKeywordImpl(C_KEYWORD) 28 | PsiElement(:)(':') 29 | CSymbolImpl(C_SYMBOL) 30 | PsiElement(sym)('c') 31 | PsiWhiteSpace(' ') 32 | CLiteralImpl(C_LITERAL) 33 | PsiElement(number)('2') 34 | PsiElement(})('}') 35 | PsiWhiteSpace(' ') 36 | CMapImpl(C_MAP) 37 | CReaderMacroImpl(C_READER_MACRO) 38 | PsiElement(#:)('#') 39 | PsiElement(::)('::') 40 | CSymbolImpl(C_SYMBOL) 41 | PsiElement(sym)('as') 42 | PsiWhiteSpace(' ') 43 | PsiElement({)('{') 44 | PsiElement(})('}') 45 | PsiWhiteSpace(' ') 46 | CKeywordImpl(C_KEYWORD) 47 | PsiElement(:)(':') 48 | CSymbolImpl(C_SYMBOL) 49 | PsiElement(sym)('s1') 50 | PsiWhiteSpace(' ') 51 | CMapImpl(C_MAP) 52 | CReaderMacroImpl(C_READER_MACRO) 53 | PsiElement(#:)('#') 54 | PsiElement(::)('::') 55 | PsiWhiteSpace(' ') 56 | PsiElement({)('{') 57 | PsiElement(})('}') 58 | PsiWhiteSpace(' ') 59 | CKeywordImpl(C_KEYWORD) 60 | PsiElement(:)(':') 61 | CSymbolImpl(C_SYMBOL) 62 | PsiElement(sym)('s2') 63 | PsiWhiteSpace(' ') 64 | CMapImpl(C_MAP) 65 | CReaderMacroImpl(C_READER_MACRO) 66 | PsiElement(#:)('#') 67 | PsiElement(:)(':') 68 | CSymbolImpl(C_SYMBOL) 69 | PsiElement(sym)('a') 70 | PsiWhiteSpace(' ') 71 | PsiElement({)('{') 72 | PsiElement(})('}') 73 | PsiWhiteSpace(' ') 74 | CKeywordImpl(C_KEYWORD) 75 | PsiElement(:)(':') 76 | CSymbolImpl(C_SYMBOL) 77 | PsiElement(sym)('s3') 78 | PsiWhiteSpace(' ') 79 | CMapImpl(C_MAP) 80 | CReaderMacroImpl(C_READER_MACRO) 81 | PsiElement(#:)('#') 82 | PsiElement(:)(':') 83 | PsiErrorElement:no allowed 84 | PsiWhiteSpace(' ') 85 | CSymbolImpl(C_SYMBOL) 86 | PsiElement(sym)('a') 87 | PsiElement({)('{') 88 | PsiElement(})('}') 89 | PsiWhiteSpace(' ') 90 | CKeywordImpl(C_KEYWORD) 91 | PsiElement(:)(':') 92 | CSymbolImpl(C_SYMBOL) 93 | PsiElement(sym)('s4') 94 | PsiWhiteSpace(' ') 95 | CMapImpl(C_MAP) 96 | CReaderMacroImpl(C_READER_MACRO) 97 | PsiElement(#:)('#') 98 | PsiElement(::)('::') 99 | PsiErrorElement:no allowed 100 | PsiWhiteSpace(' ') 101 | CSymbolImpl(C_SYMBOL) 102 | PsiElement(sym)('a') 103 | PsiElement({)('{') 104 | PsiElement(})('}') 105 | PsiErrorElement:
expected 106 | 107 | PsiWhiteSpace(' ') -------------------------------------------------------------------------------- /testData/parser/SimpleFixes.txt: -------------------------------------------------------------------------------- 1 | CFileImpl:a.clj 2 | CAccessImpl(C_ACCESS) 3 | PsiElement(.)('.') 4 | CSymbolImpl(C_SYMBOL) 5 | PsiElement(sym)('1') 6 | PsiWhiteSpace(' ') 7 | CSymbolImpl(C_SYMBOL) 8 | PsiElement(sym)('x') 9 | PsiWhiteSpace(' ') 10 | CSymbolImpl(C_SYMBOL) 11 | PsiElement(sym)('.-') 12 | PsiComment(C_LINE_COMMENT)(';comment') 13 | PsiWhiteSpace('\n') 14 | CSymbolImpl(C_SYMBOL) 15 | PsiElement(sym)('a'b') 16 | CLiteralImpl(C_LITERAL) 17 | PsiElement(string)('""') 18 | CSymbolImpl(C_SYMBOL) 19 | PsiElement(sym)('a') 20 | CLiteralImpl(C_LITERAL) 21 | PsiElement(string)('""') 22 | CSymbolImpl(C_SYMBOL) 23 | PsiElement(sym)('+') 24 | PsiWhiteSpace('\n') 25 | CLiteralImpl(C_LITERAL) 26 | PsiElement(number)('1') 27 | PsiComment(C_LINE_COMMENT)(';unclosed eof') 28 | PsiWhiteSpace('\n') 29 | PsiErrorElement:'"x' unexpected 30 | PsiElement(BAD_CHARACTER)('"x') -------------------------------------------------------------------------------- /testData/parser/SimpleRecover.txt: -------------------------------------------------------------------------------- 1 | CFileImpl:a.clj 2 | PsiErrorElement: expected, got '////' 3 | PsiElement(BAD_CHARACTER)('////') 4 | PsiWhiteSpace(' ') 5 | CLiteralImpl(C_LITERAL) 6 | PsiElement(number)('42') 7 | PsiWhiteSpace(' ') 8 | CKeywordImpl(C_KEYWORD) 9 | PsiElement(:)(':') 10 | PsiErrorElement:no allowed 11 | PsiWhiteSpace(' ') 12 | CSymbolImpl(C_SYMBOL) 13 | PsiElement(sym)('x') 14 | PsiWhiteSpace(' ') 15 | CListImpl(C_LIST) 16 | PsiElement(()('(') 17 | CSymbolImpl(C_SYMBOL) 18 | PsiElement(sym)('abc') 19 | PsiWhiteSpace(' ') 20 | CVecImpl(C_VEC) 21 | PsiElement([)('[') 22 | CKeywordImpl(C_KEYWORD) 23 | PsiElement(:)(':') 24 | PsiErrorElement:no allowed 25 | PsiWhiteSpace(' ') 26 | CSymbolImpl(C_SYMBOL) 27 | PsiElement(sym)('x') 28 | PsiWhiteSpace(' ') 29 | CKeywordImpl(C_KEYWORD) 30 | PsiElement(:)(':') 31 | PsiErrorElement:no allowed 32 | PsiWhiteSpace(' ') 33 | CSymbolImpl(C_SYMBOL) 34 | PsiElement(sym)('y') 35 | PsiWhiteSpace(' ') 36 | CSymbolImpl(C_SYMBOL) 37 | PsiElement(sym)('z') 38 | PsiElement(])(']') 39 | PsiWhiteSpace(' ') 40 | CLiteralImpl(C_LITERAL) 41 | PsiElement(ratio)('2/3') 42 | PsiElement())(')') 43 | PsiWhiteSpace(' ') 44 | PsiErrorElement:')' unexpected 45 | PsiElement())(')') 46 | CLiteralImpl(C_LITERAL) 47 | PsiElement(number)('1') 48 | PsiWhiteSpace(' ') 49 | CSymbolImpl(C_SYMBOL) 50 | PsiElement(sym)('sym') 51 | PsiErrorElement:'.' expected, got ')' 52 | PsiElement())(')') -------------------------------------------------------------------------------- /testData/parser/SimpleRecover2.txt: -------------------------------------------------------------------------------- 1 | CFileImpl:a.clj 2 | CListImpl(C_LIST) 3 | PsiElement(()('(') 4 | CSymbolImpl(C_SYMBOL) 5 | PsiElement(sym)('a') 6 | PsiElement())(')') 7 | PsiErrorElement:')' unexpected 8 | PsiElement())(')') 9 | CListImpl(C_LIST) 10 | PsiElement(()('(') 11 | CSymbolImpl(C_SYMBOL) 12 | PsiElement(sym)('b') 13 | PsiElement())(')') -------------------------------------------------------------------------------- /tests/lang/completion-tests.kt: -------------------------------------------------------------------------------- 1 | package org.intellij.clojure.lang 2 | 3 | import com.intellij.codeInsight.completion.CompletionType 4 | import com.intellij.codeInsight.lookup.Lookup.REPLACE_SELECT_CHAR 5 | import com.intellij.openapi.util.registry.Registry 6 | import com.intellij.testFramework.fixtures.BasePlatformTestCase 7 | 8 | /** 9 | * @author gregsh 10 | */ 11 | class ClojureCompletionTest : BasePlatformTestCase() { 12 | companion object { 13 | val NS_KEY = "namespace/keyword" 14 | val NS_ALIAS = "(alias 'namespace 'some-ns)" 15 | val STR_ALIAS = "(alias 'str 'clojure.string)" 16 | } 17 | 18 | override fun setUp() { 19 | super.setUp() 20 | Registry.get("ide.completion.variant.limit").setValue(10000) 21 | } 22 | 23 | fun testCoreNs1() = doTest("", "clojure.core", "clojure.core") 24 | fun testCoreNs2() = doTest(":", "clojure.core", ":clojure.core") 25 | fun testCoreDefn1() = doTest("()", "defn", "(defn)") 26 | 27 | fun testRefsInBindings1() = doNegTest("(let [abc 10 ])", "abc") 28 | fun testRefsInBindings2() = doNegTest("(let [abc 10 ])", "clojure.core") 29 | fun testRefsInBindings3() = doTest("(let [abc 10 edf ])", "abc") 30 | fun testRefsInBindings4() = doTest("(let [{:keys []} m])", "clojure.core") 31 | 32 | fun testNothingInName() = doNegTest("(def strip) (def stri)", "clo-def", "clojure.string", ":strict") 33 | 34 | fun testKeyword1() = ":keyword".let { doPosTest("$it :", it) } 35 | fun testKeyword2() = ":keyword".let { doTest("$it :key", it, "$it $it") } 36 | fun testKeyword3() = ":keyword".let { doNegTest("$it ", it) } 37 | fun testKeyword4() = ":keyword".let { doNegTest("$it ${it}11 ${it}22 $it", it) } 38 | fun testKeyword5() = ":namespace/keyword".let { doNegTest("$it ${it}11 ${it}22 $it", it) } 39 | fun testKeywordMeta1() = ":keyword".let { doPosTest("^meta $it ^meta :", it) } 40 | fun testKeywordMeta2() = ":keyword".let { doTest("^meta $it ^meta :key", it, "^meta $it ^meta $it") } 41 | fun testKeywordUser1() = "::keyword".let { doTest("$it :", it, "$it $it") } 42 | fun testKeywordUser2() = "::keyword".let { doTest("$it ::key", it, "$it $it") } 43 | fun testKeywordUser3() = "::keyword".let { doNegTest("$it ", it) } 44 | fun testKeywordNs1() = ":$NS_KEY".let { doPosTest("$it :", it) } 45 | fun testKeywordNs2() = ":$NS_KEY".let { doTest("$it :key", it, "$it $it") } 46 | fun testKeywordNs3() = ":$NS_KEY".let { doNegTest("$it ", it) } 47 | fun testKeywordNs4() = ":$NS_KEY".let { doTest("$it :namespace/", it, "$it $it") } 48 | fun testKeywordNs5() = ":$NS_KEY".let { doTest("$it :namespace/key", it, "$it $it") } 49 | fun testKeywordNs6() = ":$NS_KEY".let { doTest("$it :name", it, "$it $it") } 50 | fun testKeywordNs7() = ":$NS_KEY".let { doTest("$it :nk", it, "$it $it") } 51 | fun testKeywordNs8() = ":$NS_KEY".let { doNegTest("$it nk", it) } 52 | fun testKeywordNsUser1() = "::$NS_KEY".let { doTest("$NS_ALIAS $it :", it, "$NS_ALIAS $it $it") } 53 | fun testKeywordNsUser2() = "::$NS_KEY".let { doTest("$NS_ALIAS $it :key", it, "$NS_ALIAS $it $it") } 54 | fun testKeywordNsUser3() = "::$NS_KEY".let { doNegTest("$NS_ALIAS $it ", it) } 55 | fun testKeywordNsUser4() = "::$NS_KEY".let { doTest("$NS_ALIAS $it ::namespace/", it, "$NS_ALIAS $it $it") } 56 | fun testKeywordNsUser5() = "::$NS_KEY".let { doTest("$NS_ALIAS $it ::namespace/key", it, "$NS_ALIAS $it $it") } 57 | fun testKeywordNsUser6() = "::$NS_KEY".let { doTest("$NS_ALIAS $it ::name", it, "$NS_ALIAS $it $it") } 58 | fun testKeywordNsUser8() = "::$NS_KEY".let { doTest("$NS_ALIAS $it ::nk", it, "$NS_ALIAS $it $it") } 59 | fun testKeywordNsUser4a() = "::$NS_KEY".let { doTest("$NS_ALIAS $it :some-ns/", it, "$NS_ALIAS $it ::namespace/keyword") } 60 | fun testKeywordNsUser5a() = "::$NS_KEY".let { doTest("$NS_ALIAS $it :some-ns/key", it, "$NS_ALIAS $it ::namespace/keyword") } 61 | fun testKeywordNsUser6a() = "::$NS_KEY".let { doTest("$NS_ALIAS $it :some", it, "$NS_ALIAS $it $it") } 62 | fun testKeywordNsUser8a() = "::$NS_KEY".let { doTest("$NS_ALIAS $it :sk", it, "$NS_ALIAS $it $it") } 63 | fun testKeywordNsUser9() = "::$NS_KEY".let { doNegTest("$NS_ALIAS $it nk", it) } 64 | 65 | fun testNsAlias1() = "namespace".let { doPosTest("$NS_ALIAS (", it) } 66 | fun testNsAlias2() = "namespace".let { doPosTest("$NS_ALIAS (/", it) } 67 | fun testNsAlias3() = "namespace".let { doPosTest("$NS_ALIAS (/xxx", it) } 68 | fun testNsAlias4() = "namespace".let { doPosTest("$NS_ALIAS (nam", it) } 69 | fun testNsAlias5() = "namespace".let { doPosTest("$NS_ALIAS (nam/", it) } 70 | fun testNsAlias6() = "namespace".let { doPosTest("$NS_ALIAS (nam/xxx", it) } 71 | 72 | fun testFqn1() = doTest("(clojure.string/)", "blank?", "(clojure.string/blank?)") 73 | fun testFqn2() = "clojure.string/blank?".let { doTest("(bla)", it, "($it)", 2) } 74 | fun testFqn3() = "clojure.string/blank?".let { doTest("(clostribla)", it, "($it)", 2) } 75 | fun testFqn4() = doTest("(clojure.string/blank?)", "clojure.string", "(clojure.string/blank?)") 76 | fun testFqn2a() = "str/blank?".let { doTest("$STR_ALIAS (bla)", it, "$STR_ALIAS ($it)", 2) } 77 | fun testFqn3a() = "str/blank?".let { doTest("$STR_ALIAS (clostribla)", it, "$STR_ALIAS ($it)", 2) } 78 | fun testFqn4a() = doTest("$STR_ALIAS (str/blank?)", "str", "$STR_ALIAS (str/blank?)") 79 | 80 | fun testInsideImport1() = doTest("(require '[ :refer [blank?]])", "clojure.string") 81 | fun testInsideImport2() = doNegTest("(require '[ :refer [blank?]])", "def") 82 | fun testInsideImport3() = doTest("(require '[clojure.string :refer []])", "blank?") 83 | fun testInsideImport4() = doNegTest("(require '[clojure.string :refer []])", "def") 84 | 85 | fun testJava1() = doPosTest("(defn a [^java.util.SortedSet a] (. a))", "comparator", "size", "contains", "add") 86 | 87 | 88 | private fun doTest(text: String, select: String, 89 | expected: String = text.replace("", select), 90 | count: Int = 1) = myFixture.run { 91 | configureByText("a.clj", text) 92 | complete(CompletionType.BASIC, count)?.let { variants -> 93 | val chosen = variants.find { it.lookupString == select } 94 | assertNotNull("'$select' variant not suggested", chosen) 95 | lookup.currentItem = chosen 96 | finishLookup(REPLACE_SELECT_CHAR) 97 | } 98 | checkResult(expected) 99 | } 100 | 101 | private fun doNegTest(text: String, vararg select: String) = myFixture.run { 102 | configureByText("a.clj", text) 103 | complete(CompletionType.BASIC, 1) 104 | select.forEach { it -> assertFalse("'$it' unexpected", lookupElementStrings?.contains(it) ?: false) } 105 | checkResult(text) 106 | } 107 | 108 | private fun doPosTest(text: String, vararg select: String) = myFixture.run { 109 | configureByText("a.clj", text) 110 | complete(CompletionType.BASIC, 1) 111 | select.forEach { it -> assertTrue("'$it' expected", lookupElementStrings?.contains(it) ?: false) } 112 | checkResult(text) 113 | } 114 | } -------------------------------------------------------------------------------- /tests/lang/formatter-tests.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.lang 19 | 20 | import com.intellij.application.options.CodeStyle 21 | import com.intellij.openapi.command.WriteCommandAction 22 | import com.intellij.openapi.util.text.StringUtil.escapeToRegexp 23 | import com.intellij.openapi.util.text.StringUtil.nullize 24 | import com.intellij.psi.codeStyle.CodeStyleManager 25 | import com.intellij.psi.codeStyle.CodeStyleSettingsManager 26 | import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider 27 | import com.intellij.testFramework.ParsingTestCase 28 | import com.intellij.testFramework.fixtures.BasePlatformTestCase 29 | import groovy.lang.Binding 30 | import groovy.lang.GroovyShell 31 | import org.intellij.clojure.formatter.ClojureCodeStyleSettings 32 | import org.intellij.clojure.ui.formatter.ClojureLangCodeStyleSettingsProvider 33 | 34 | /** 35 | * @author gregsh 36 | */ 37 | const val DELIMITER = ";;; reformat>" 38 | 39 | class ClojureFormatterTest : BasePlatformTestCase() { 40 | override fun getTestDataPath() = "$TEST_DATA_PATH/formatter" 41 | 42 | private val settingsManager: CodeStyleSettingsManager get() = CodeStyleSettingsManager.getInstance(project) 43 | 44 | override fun setUp() { 45 | super.setUp() 46 | val settings = CodeStyleSettingsManager.getInstance(project).cloneSettings(CodeStyle.getSettings(project)) 47 | settingsManager.setTemporarySettings(settings) 48 | } 49 | 50 | override fun tearDown() { 51 | settingsManager.dropTemporarySettings() 52 | super.tearDown() 53 | } 54 | 55 | fun testSimple() = doTest() 56 | fun testStyleGuide() = doTest() 57 | fun testFormatterFixes() = doTest() 58 | 59 | fun testCodeSample() = doTest(ClojureLangCodeStyleSettingsProvider().getCodeSample( 60 | LanguageCodeStyleSettingsProvider.SettingsType.INDENT_SETTINGS)) 61 | 62 | private fun doTest() = myFixture.run { 63 | val fileName = getTestName(false) + ".clj" 64 | val fullText = ParsingTestCase.loadFileDefault(testDataPath, fileName) 65 | 66 | val match = "\n*(?:${escapeToRegexp(DELIMITER)}.*\n*)++".toRegex().find(fullText) 67 | ?: error("separate before/after snippets with:\n$DELIMITER") 68 | nullize(fullText.substring(match.range).trimMargin(DELIMITER).trim())?.let { evaluate(it)} 69 | val original = fullText.substring(0, match.range.first) 70 | val performEnter = original.contains("") 71 | configureByText(ClojureFileType, original) 72 | WriteCommandAction.runWriteCommandAction(null) { 73 | if (performEnter) type("\n") 74 | else CodeStyleManager.getInstance(project).reformat(file) 75 | } 76 | WriteCommandAction.runWriteCommandAction(null) { 77 | editor.document.run { 78 | insertString(0, fullText.substring(0, match.range.last + 1)) 79 | } 80 | } 81 | checkResultByFile(fileName, true) 82 | } 83 | 84 | private fun doTest(original: String) = myFixture.run { 85 | configureByText(ClojureFileType, original) 86 | val performEnter = original.contains("") 87 | WriteCommandAction.runWriteCommandAction(null) { 88 | if (performEnter) type("\n") 89 | else CodeStyleManager.getInstance(project).reformat(file) 90 | } 91 | checkResultByFile(getTestName(false) + ".clj", true) 92 | } 93 | 94 | private fun evaluate(script : String) { 95 | val tmpSettings = settingsManager.temporarySettings!! 96 | val common = tmpSettings.getCommonSettings(ClojureLanguage) 97 | val custom = tmpSettings.getCustomSettings(ClojureCodeStyleSettings::class.java) 98 | val binding = Binding(mutableMapOf( 99 | "main" to tmpSettings, 100 | "common" to common, 101 | "custom" to custom)) 102 | GroovyShell(binding).evaluate(script) 103 | } 104 | } -------------------------------------------------------------------------------- /tests/lang/highlighting-tests.kt: -------------------------------------------------------------------------------- 1 | package org.intellij.clojure.lang 2 | 3 | /** 4 | * @author gregsh 5 | */ 6 | -------------------------------------------------------------------------------- /tests/lang/refactoring-tests.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.lang 19 | 20 | import com.intellij.refactoring.BaseRefactoringProcessor 21 | import com.intellij.testFramework.fixtures.BasePlatformTestCase 22 | 23 | /** 24 | * 25 | * 26 | * @author gregsh 27 | */ 28 | class ClojureRenameTest : BasePlatformTestCase() { 29 | fun testRename1() = doTest("Bar", "(defrecord Foo| [a b]) (Foo. 1 2)") 30 | fun testRenameKey1() = doTest("foo", "::bar|\n\n(defn A [{::keys [bar]}] (print bar some/foo)))") 31 | fun testRenameKey2() = doFailTest("foo", "::bar| (defn A [{::keys [bar]}] (let [foo 12] (print bar))))") 32 | 33 | private fun doTest(newName: String, before: String, 34 | after: String = defaultRename(newName, before)) { 35 | myFixture.configureByText("a.clj", before.replace("|", "")) 36 | myFixture.renameElementAtCaret(newName) 37 | myFixture.checkResult(after) 38 | } 39 | 40 | private fun doFailTest(newName: String, before: String) { 41 | try { doTest(newName, before, before) } 42 | catch (e : BaseRefactoringProcessor.ConflictsInTestsException) { return } 43 | fail("should fail") 44 | } 45 | 46 | private fun defaultRename(newName: String, str: String): String { 47 | val oldName = "(\\w+)\\|".toRegex().find(str)?.groups?.get(1)?.value!! 48 | return str.replace(oldName, newName).replace("|", "") 49 | } 50 | } -------------------------------------------------------------------------------- /tests/lang/test-util.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.lang 19 | 20 | import com.intellij.openapi.util.JDOMUtil 21 | import com.intellij.openapi.util.io.FileUtil 22 | import com.intellij.openapi.util.io.FileUtilRt 23 | import com.intellij.openapi.util.text.StringUtil 24 | import com.intellij.openapi.util.text.StringUtilRt 25 | import com.intellij.openapi.vfs.CharsetToolkit 26 | import com.intellij.openapi.vfs.VfsUtil 27 | import com.intellij.openapi.vfs.VirtualFile 28 | import com.intellij.openapi.vfs.VirtualFileManager 29 | import java.io.File 30 | import java.io.InputStreamReader 31 | 32 | /** 33 | * @author gregsh 34 | */ 35 | val TEST_DATA_PATH = FileUtil.toSystemIndependentName(File("testData").absolutePath) 36 | val CLOJURE_LIB = "Clojure" 37 | val CLOJURE_SCRIPT_LIB = "ClojureScript" 38 | 39 | fun getLibrarySources(libName: String) = getLibraryUrls(libName) 40 | .mapNotNull { VirtualFileManager.getInstance().findFileByUrl(it) } 41 | .flatMap { VfsUtil.collectChildrenRecursively(it) } 42 | .filter { FileUtilRt.getExtension(it.name).startsWith("clj") } 43 | .sortedBy { it.path } 44 | 45 | fun getLibraryUrls(libName: String) = JDOMUtil.load(File(".idea/libraries/$libName.xml")) 46 | .getChild("library").getChild("CLASSES").getChildren("root") 47 | .mapNotNull { it.getAttributeValue("url") } 48 | .map { StringUtil.trimEnd(it, "!/") } 49 | .map { it.substring(it.lastIndexOf("/") + 1) } 50 | .mapNotNull { 51 | val cp = System.getProperty("java.class.path") 52 | val idx = cp.indexOf(it) 53 | if (idx == -1) return@mapNotNull null 54 | val path = cp.substring(cp.substring(0, idx).lastIndexOf(File.pathSeparator) + 1, idx + it.length) 55 | "jar://$path!/" 56 | } 57 | 58 | fun getFileText(vFile: VirtualFile) : Pair { 59 | val path = vFile.path.substring(vFile.path.indexOf("!/") + 2) 60 | val text = StringUtilRt.convertLineSeparators(FileUtil.loadTextAndClose( 61 | InputStreamReader(vFile.inputStream, CharsetToolkit.UTF8)).trim { it <= ' ' }) 62 | return Pair(path, text) 63 | } -------------------------------------------------------------------------------- /tests/lang/usages-tests.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present Greg Shrago 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | package org.intellij.clojure.lang 19 | 20 | import com.intellij.codeInsight.TargetElementUtil 21 | import com.intellij.testFramework.fixtures.BasePlatformTestCase 22 | import junit.framework.TestCase 23 | 24 | 25 | class ClojureUsagesTest : BasePlatformTestCase() { 26 | companion object { 27 | const val NS_ALIAS = "(alias 'bar 'foo.bar)" 28 | } 29 | 30 | fun testKeywordUsages1() = doTest("(let [{:keys [x y]} {:x| 42}] y)", 2) 31 | fun testKeywordUsages2() = doTest("$NS_ALIAS (let [{::bar/keys [x y]} {::bar/x| 42}] y)", 2) 32 | fun testKeywordUsages3a() = doTest("$NS_ALIAS (let [{:keys [foo.bar/x y]} {::bar/x| 42}] y)", 2) 33 | fun testKeywordUsages3b() = doTest("$NS_ALIAS (let [{:keys [x y]} {::bar/x| 42}] y)", 1) 34 | fun testDeftypeField1() = doTest("(deftype A [x| y]) (.-x (A.)) (. (A.) -x)", 3) 35 | fun testDeftypeField2() = doTest("(deftype A [^A x|]) (.-x (. (A.) -x))", 3) 36 | 37 | private fun doTest(text: String, expectedCount: Int) = myFixture.run { 38 | configureByText("a.clj", text.replace("|", "")) 39 | val flags = TargetElementUtil.ELEMENT_NAME_ACCEPTED or TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED 40 | val element = TargetElementUtil.findTargetElement(myFixture.editor, flags) 41 | TestCase.assertEquals(expectedCount, findUsages(element!!).size) 42 | } 43 | } --------------------------------------------------------------------------------