diff --git a/.emmyrc.json b/.emmyrc.json deleted file mode 100644 index 2c67b9855..000000000 --- a/.emmyrc.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json", - "format": { - "externalTool": { - "program": "stylua", - "args": [ - "-", - "--stdin-filepath", - "${file}" - ] - } - }, - "diagnostics": { - "disable": [ - "unnecessary-if", - "incomplete-signature-doc" - ], - "enables": [ - "iter-variable-reassign", - "non-literal-expressions-in-assert", - "missing-global-doc" - ] - }, - "codeAction": { - "insertSpace": true - }, - "strict": { - "typeCall": true, - "arrayIndex": true - } -} diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index f88a2024f..000000000 --- a/.gitattributes +++ /dev/null @@ -1,4 +0,0 @@ -runtime/queries/**/*.scm linguist-language=tsq -doc/*.txt linguist-documentation -SUPPORTED_LANGUAGES.md linguist-generated -lua/nvim-treesitter/async.lua linguist-vendored diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..8fcb7cd9e --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,7 @@ +/lua/nvim-treesitter/textobjects/ @theHamsta +/lua/nvim-treesitter/incremental_selection.lua @theHamsta + +/lua/nvim-treesitter/fold.lua @vigoux +/lua/nvim-treesitter/highlight.lua @vigoux + +/lua/nvim-treesitter/refactor/ @steelsojka diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..b2844b214 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +open_collective: "nvim-treesitter" +github: "nvim-treesitter" diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 78ce29cd6..0b6c990a9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug report description: Create a report to help us improve -type: 'bug' +labels: [ bug ] body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 1f87c07b4..11fc491ef 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,9 +1,10 @@ --- name: Feature request about: Suggest an idea for this project -title: "" -type: enhancement -assignees: "" +title: '' +labels: enhancement +assignees: '' + --- **Is your feature request related to a problem? Please describe.** diff --git a/.github/ISSUE_TEMPLATE/highlighting_issue.yml b/.github/ISSUE_TEMPLATE/highlighting_issue.yml index 4b9b0a4a7..b6c4404fc 100644 --- a/.github/ISSUE_TEMPLATE/highlighting_issue.yml +++ b/.github/ISSUE_TEMPLATE/highlighting_issue.yml @@ -1,7 +1,6 @@ name: Highlighting issue description: Missing or incorrect highlights or you want to change the way something is highlighted -type: 'bug' -labels: [highlights] +labels: [ highlights ] body: - type: markdown @@ -12,10 +11,10 @@ body: - I have updated my neovim version to latest _master_. - I have updated my plugin to the latest version. - I have run `:TSUpdate`. - - I have inspected the syntax tree using `:InspectTree` and made sure + - I have inspected the syntax tree using https://github.com/nvim-treesitter/playground and made sure that no `ERROR` nodes are in the syntax tree. nvim-treesitter can not guarantee correct highlighting in the presence of `ERROR`s -- in this case, please report the bug directly at corresponding parser's repository. (You can find all repository URLs in [README.md](https://github.com/nvim-treesitter/nvim-treesitter#supported-languages).) - - I have used `:Inspect` to inspect which highlight groups Neovim is using and that legacy syntax highlighting is not interfering (i.e., what you are observing is actual tree-sitter highlighting). + - I have used `:TSHighlightCapturesUnderCursor` from https://github.com/nvim-treesitter/playground to inspect which highlight groups Neovim is using and that legacy syntax highlighting is not interfering (i.e., what you are observing is actual tree-sitter highlighting). - type: textarea attributes: @@ -35,8 +34,8 @@ body: attributes: label: Tree-sitter parsing result description: | - Please provide the output of `:InspectTree` (screenshot or plain text) - with the following options enabled (pressing the key): + Please provide the output of `:TSPlaygroundToggle` from https://github.com/nvim-treesitter/playground + (screenshot or plain text) with the following options enabled (pressing the key): - `I` (name of the parsed language) - `t` (toggle injected languages) - `a` (show anonymous nodes) @@ -67,7 +66,7 @@ body: description: | Please provide a screenshot of the current highlighting. Please also tell us the `:h colorscheme` you are using and how to install it. If applicable, you can also upload a screenshot with the contents of - `:Inspect`. + `:TSHighlightCapturesUnderCursor`. validations: required: true diff --git a/.github/PULL_REQUEST_TEMPLATE/new_language.md b/.github/PULL_REQUEST_TEMPLATE/new_language.md deleted file mode 100644 index b35e84b3b..000000000 --- a/.github/PULL_REQUEST_TEMPLATE/new_language.md +++ /dev/null @@ -1,47 +0,0 @@ - - -# Name of language - - -https://... - -Language file extension, if applicable: (e.g. `.zu`) - -
-Representative code sample -``` -max. 50 lines -``` -
- -## Parser repo - -https://github.com/... - -
-Parsed tree for code sample -``` -paste output of tree-sitter parse or :InspectTree here -``` -
- -## Queries - -Source of queries: https://github.com/... (or "written from scratch") - -
-Screenshots of code sample - -
- - diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index e80604577..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,16 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - cooldown: - default-days: 3 - commit-message: - prefix: "ci" - labels: - - "CI" - groups: - actions: - patterns: ["*"] - diff --git a/.github/mergify.yml b/.github/mergify.yml new file mode 100644 index 000000000..b95a074a5 --- /dev/null +++ b/.github/mergify.yml @@ -0,0 +1,37 @@ +pull_request_rules: + - name: Merge lockfile updates + conditions: + - "title=Update lockfile.json" + actions: + review: + type: APPROVE + message: Automatically approving lockfile updates + merge: + method: merge + + - name: Prepare for merge + conditions: + - and: + - "-draft" + - "#approved-reviews-by=1" + - "#review-requested=0" + actions: + comment: + message: | + This PR is ready to be merged, and will be in 1 day if nothing happens before. + If you want other people to review your PR, request their reviews. + If you don't want this PR to be merged now, mark it as a Draft. + + - name: Merge on approval + conditions: + - and: + - or: + - "#approved-reviews-by>=2" + - and: + - "#approved-reviews-by=1" + - "updated-at>=1 day ago" + - "-draft" + - "#review-requested=0" + actions: + merge: + method: rebase diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 1f5207d98..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/.github/workflows/downstream.yml b/.github/workflows/downstream.yml deleted file mode 100644 index 46e699613..000000000 --- a/.github/workflows/downstream.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Tests - -on: - pull_request: - branches: - - "main" - paths: - - "lua/nvim-treesitter/parsers.lua" - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - -jobs: - test-downstream: - name: Check downstream queries - runs-on: ubuntu-latest - env: - NVIM: "nvim" - steps: - - uses: actions/checkout@v6 - - uses: tree-sitter/setup-action/cli@v2 - - - name: Install and prepare Neovim - env: - NVIM_TAG: "nightly" - run: | - bash ./scripts/ci-install.sh - - - name: Compile parsers - run: $NVIM -l ./scripts/install-parsers.lua --max-jobs=10 - - - name: Set up ts_query_ls - run: curl -fL https://github.com/ribru17/ts_query_ls/releases/latest/download/ts_query_ls-x86_64-unknown-linux-gnu.tar.gz | tar -xz - - - name: Clone textobjects - uses: actions/checkout@v6 - with: - repository: nvim-treesitter/nvim-treesitter-textobjects - ref: main - path: .tests/nvim-treesitter-textobjects - sparse-checkout: queries - - - name: Check textobjects - working-directory: .tests/nvim-treesitter-textobjects/ - run: ../../ts_query_ls check queries/ - - - name: Clone context - if: always() - uses: actions/checkout@v6 - with: - repository: nvim-treesitter/nvim-treesitter-context - ref: master - path: .tests/nvim-treesitter-context - sparse-checkout: queries - - - name: Check context - if: always() - working-directory: .tests/nvim-treesitter-context/ - run: ../../ts_query_ls check queries/ - diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6ed8e7ba2..8d0bb121f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,50 +1,33 @@ -name: Lint +name: Linting and style checking -on: +on: push: - branches: - - "main" pull_request: - branches: - - "main" - workflow_dispatch: + types: [opened, synchronize, reopened, ready_for_review] jobs: - lua: - name: Lint Lua files - runs-on: ubuntu-slim + luacheck: + name: Luacheck + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v2 - - name: Format + - name: Prepare run: | - make formatlua - git diff --exit-code + sudo apt-get update + sudo apt-get install luarocks -y + sudo luarocks install luacheck - - name: Lint - run: make checklua + - name: Run Luacheck + run: luacheck . - queries: - name: Lint query files - runs-on: ubuntu-slim + stylua: + name: StyLua + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - - name: Format - run: | - make formatquery - git diff --exit-code - - - name: Lint - run: make lintquery - - readme: - name: Lint docs - runs-on: ubuntu-slim - steps: - - uses: actions/checkout@v6 - - - name: Check SUPPORTED_LANGUAGES - run: | - make docs - git diff --exit-code + - uses: actions/checkout@v2 + - name: Lint with stylua + uses: JohnnyMorganz/stylua-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --check . diff --git a/.github/workflows/test-core.yml b/.github/workflows/test-core.yml deleted file mode 100644 index 0332f479a..000000000 --- a/.github/workflows/test-core.yml +++ /dev/null @@ -1,58 +0,0 @@ -on: - workflow_call: - inputs: - type: - type: string - workflow_dispatch: - -defaults: - run: - shell: bash - -jobs: - check_compilation: - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - nvim_tag: [stable, nightly] - name: ${{matrix.nvim_tag}} / ${{ matrix.os }} - runs-on: ${{ matrix.os }} - env: - NVIM: ${{ matrix.os == 'windows-latest' && 'nvim-win64\\bin\\nvim.exe' || 'nvim' }} - steps: - - uses: actions/checkout@v6 - - uses: tree-sitter/setup-action/cli@v2 - - - name: Install and prepare Neovim - env: - NVIM_TAG: ${{ matrix.nvim_tag }} - run: | - bash ./scripts/ci-install.sh - - - if: inputs.type == 'build' - name: Compile parsers - run: $NVIM -l ./scripts/install-parsers.lua --max-jobs=10 - - - if: inputs.type == 'generate' - name: Generate and compile parsers - run: $NVIM -l ./scripts/install-parsers.lua --generate --max-jobs=2 - - - name: Check parsers - run: $NVIM -l ./scripts/check-parsers.lua - - - name: Check queries (nvim) - if: ${{ matrix.os == 'windows-latest' }} - run: $NVIM -l ./scripts/check-queries.lua - - - name: Check queries (tsqueryls) - if: ${{ matrix.os != 'windows-latest' }} - run: make checkquery - - - name: Run highlight tests - if: ${{ matrix.os != 'windows-latest' }} - run: make tests TESTS=query NVIM_BIN=$NVIM - - - name: Run indents tests - if: ${{ matrix.os != 'windows-latest' }} - run: make tests TESTS=indent NVIM_BIN=$NVIM diff --git a/.github/workflows/test-generate.yml b/.github/workflows/test-generate.yml deleted file mode 100644 index 0735f9f2c..000000000 --- a/.github/workflows/test-generate.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Tests - -on: - pull_request: - types: [unlabeled, labeled, opened, synchronize, reopened] - branches: - - "main" - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-generate-${{ github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - -jobs: - check_compilation: - name: Generate - if: contains(github.event.pull_request.labels.*.name, 'ci:generate') || github.event_name == 'workflow_dispatch' - uses: ./.github/workflows/test-core.yml - with: - type: "generate" diff --git a/.github/workflows/test-queries.yml b/.github/workflows/test-queries.yml index 5d95bb351..738bad9a4 100644 --- a/.github/workflows/test-queries.yml +++ b/.github/workflows/test-queries.yml @@ -1,21 +1,86 @@ -name: Tests +name: Test queries on: push: branches: - - "main" + - 'master' pull_request: + types: [opened, synchronize, reopened, ready_for_review] branches: - - "main" - workflow_dispatch: + - 'master' +# Cancel any in-progress CI runs for a PR if it is updated concurrency: - group: ${{ github.workflow }}-build-${{ github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} + cancel-in-progress: true + +defaults: + run: + shell: bash jobs: check_compilation: - name: Build - uses: ./.github/workflows/test-core.yml - with: - type: "build" + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-2022, macos-latest] + cc: [ gcc, clang ] + nvim_tag: [ stable ] + exclude: + - os: ubuntu-latest + cc: clang + nvim_tag: stable + + - os: macos-latest + cc: gcc + nvim_tag: stable + + - os: windows-2022 + cc: clang + nvim_tag: stable + + include: + - os: windows-2022 + cc: cl + nvim_tag: stable + + - os: ubuntu-latest + cc: gcc + nvim_tag: nightly + + name: Parser compilation + runs-on: ${{ matrix.os }} + env: + CC: ${{ matrix.cc }} + NVIM: ${{ matrix.os == 'windows-2022' && 'nvim-win64\\bin\\nvim.exe' || 'nvim' }} + ALLOWED_INSTALLATION_FAILURES: ${{ matrix.os == 'windows-2022' && 'rnoweb' }} + steps: + - uses: actions/checkout@v2 + - uses: ilammy/msvc-dev-cmd@v1 + - uses: actions/setup-node@v2 + + - name: Install and prepare Neovim + env: + NVIM_TAG: ${{ matrix.nvim_tag }} + TREE_SITTER_CLI_TAG: v0.20.6 + run: | + bash ./scripts/ci-install-${{ matrix.os }}.sh + + - name: Setup Parsers Cache + id: parsers-cache + uses: actions/cache@v2 + with: + path: | + ./parser/ + ~/AppData/Local/nvim/pack/nvim-treesitter/start/nvim-treesitter/parser/ + key: ${{ matrix.os }}-${{ matrix.cc }}-${{ matrix.nvim_tag }}-parsers-v1-${{ hashFiles('./lockfile.json', './lua/nvim-treesitter/parsers.lua', './lua/nvim-treesitter/install.lua', './lua/nvim-treesitter/shell_selectors.lua') }} + + - name: Compile parsers + run: $NVIM --headless -c "lua require'nvim-treesitter.install'.prefer_git=false" -c "TSInstallSync all" -c "q" + + - name: Post compile Windows + if: matrix.os == 'windows-2022' + run: cp -r ~/AppData/Local/nvim/pack/nvim-treesitter/start/nvim-treesitter/parser/* parser + + - name: Check query files + run: $NVIM --headless -c "luafile ./scripts/check-queries.lua" -c "q" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..e8f462119 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,63 @@ +name: Tests + +on: + push: + branches: + - 'master' + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + branches: + - 'master' + +# Cancel any in-progress CI runs for a PR if it is updated +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} + cancel-in-progress: true + +jobs: + check_compilation: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + cc: [ gcc ] + + name: Run tests + runs-on: ${{ matrix.os }} + env: + CC: ${{ matrix.cc }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + + - name: Test Dependencies + run: | + mkdir -p ~/.local/share/nvim/site/pack/plenary.nvim/start + cd ~/.local/share/nvim/site/pack/plenary.nvim/start + git clone https://github.com/nvim-lua/plenary.nvim + curl -L https://github.com/theHamsta/highlight-assertions/releases/download/v0.1.5/highlight-assertions_v0.1.5_x86_64-unknown-linux-gnu.tar.gz | tar -xz + cp highlight-assertions /usr/local/bin + + - name: Install and prepare Neovim + env: + NVIM_TAG: stable + TREE_SITTER_CLI_TAG: v0.20.6 + run: | + bash ./scripts/ci-install-${{ matrix.os }}.sh + + - name: Setup Parsers Cache + id: parsers-cache + uses: actions/cache@v2 + with: + path: | + ./parser/ + ~/AppData/Local/nvim/pack/nvim-treesitter/start/nvim-treesitter/parser/ + key: ${{ matrix.os }}-${{ matrix.cc }}-parsers-v1-${{ hashFiles('./lockfile.json', './lua/nvim-treesitter/parsers.lua', './lua/nvim-treesitter/install.lua', './lua/nvim-treesitter/shell_selectors.lua') }} + + - name: Compile parsers Unix like + if: ${{ matrix.os != 'windows-latest' && steps.parsers-cache.outputs.cache-hit != 'true' }} + run: | + nvim --headless -c "TSInstallSync all" -c "q" + + - name: Tests + run: PATH=/usr/local/bin:$PATH ./scripts/run_tests.sh diff --git a/.github/workflows/update-lockfile.yml b/.github/workflows/update-lockfile.yml new file mode 100644 index 000000000..c3ea4515c --- /dev/null +++ b/.github/workflows/update-lockfile.yml @@ -0,0 +1,57 @@ +name: Update lockfile + +on: + schedule: + - cron: '30 6 * * *' + push: + branches: + - master + workflow_dispatch: + +jobs: + update-lockfile: + name: Update lockfile + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + ref: master + + - name: Prepare + env: + NVIM_TAG: stable + run: | + wget https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 + mv ./jq-linux64 /tmp/jq + chmod +x /tmp/jq + sudo apt install libfuse2 + wget https://github.com/neovim/neovim/releases/download/${NVIM_TAG}/nvim.appimage + chmod u+x nvim.appimage + mkdir -p ~/.local/share/nvim/site/pack/nvim-treesitter/start + ln -s $(pwd) ~/.local/share/nvim/site/pack/nvim-treesitter/start + + - name: Update parsers + env: + SKIP_LOCKFILE_UPDATE_FOR_LANGS: verilog,gleam,nix + run: | + ./nvim.appimage --headless -c "luafile ./scripts/write-lockfile.lua" -c "q" + # Pretty print + cp lockfile.json /tmp/lockfile.json + cat /tmp/lockfile.json | /tmp/jq --sort-keys > lockfile.json + + - name: Commit changes + run: | + git config user.name "GitHub" + git config user.email "noreply@github.com" + git add lockfile.json + git commit -m "Update lockfile.json" || echo 'No commit necessary!' + git clean -xf + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v3 + with: + commit-message: Update lockfile.json + title: Update lockfile.json + branch: update-lockfile-pr + base: ${{ github.head_ref }} + draft: true diff --git a/.github/workflows/update-parsers.yml b/.github/workflows/update-parsers.yml deleted file mode 100644 index 694a8bbbd..000000000 --- a/.github/workflows/update-parsers.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Update parsers - -on: - schedule: - - cron: "30 6 * * 6" - workflow_dispatch: - -env: - BIN_DIR: ${{ github.workspace }}/bin - -jobs: - update-parsers: - strategy: - fail-fast: false - matrix: - tier: [1, 2] - name: Update parsers tier ${{ matrix.tier }} - runs-on: ubuntu-slim - steps: - - uses: actions/checkout@v6 - with: - ref: main - - - uses: actions/create-github-app-token@v3 - id: app-token - with: - app-id: ${{ vars.TOKEN_ID }} - private-key: ${{ secrets.TOKEN_PRIVATE_KEY }} - - - name: Add $BIN_DIR to PATH - run: echo "$BIN_DIR" >> $GITHUB_PATH - - - name: Prepare - env: - NVIM_TAG: nightly - run: | - bash scripts/ci-install.sh - wget --directory-prefix="$BIN_DIR" https://github.com/JohnnyMorganz/StyLua/releases/latest/download/stylua-linux-x86_64.zip - (cd "$BIN_DIR"; unzip stylua*.zip) - - - name: Update parsers - run: ./scripts/update-parsers.lua --tier=${{ matrix.tier }} - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v8 - with: - add-paths: lua/nvim-treesitter/parsers.lua - token: ${{ steps.app-token.outputs.token }} - sign-commits: true - commit-message: "bot(parsers): update ${{ env.UPDATED_PARSERS }}" - title: "Update parsers (tier ${{ matrix.tier }}): ${{ env.UPDATED_PARSERS }}" - body: "[beep boop](https://github.com/peter-evans/create-pull-request)" - branch: update-parsers-tier-${{ matrix.tier }} - base: ${{ github.head_ref }} - - - name: Enable Pull Request Automerge - if: ${{ matrix.tier == 2 }} - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: gh pr merge --rebase --auto update-parsers-tier-2 diff --git a/.github/workflows/update-readme.yml b/.github/workflows/update-readme.yml new file mode 100644 index 000000000..62f8bd4fc --- /dev/null +++ b/.github/workflows/update-readme.yml @@ -0,0 +1,41 @@ +name: Update README + +on: + push: + branches: + - master + workflow_dispatch: + +jobs: + update-readme: + name: Update README + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Prepare + env: + NVIM_TAG: stable + run: | + wget https://github.com/neovim/neovim/releases/download/${NVIM_TAG}/nvim.appimage + chmod u+x nvim.appimage + mkdir -p ~/.local/share/nvim/site/pack/nvim-treesitter/start + ln -s $(pwd) ~/.local/share/nvim/site/pack/nvim-treesitter/start + + - name: Check README + run: | + git config user.email "actions@github" + git config user.name "Github Actions" + ./nvim.appimage --headless -c "luafile ./scripts/update-readme.lua" -c "q" || echo "Needs update" + git add README.md + git commit -m "Update README" || echo 'No commit necessary!' + git clean -xf + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v3 + with: + commit-message: Update README + title: Update README + branch: update-readme-pr + base: ${{ github.head_ref }} + draft: true diff --git a/.gitignore b/.gitignore index ca538329d..6e01dc63c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,4 @@ -.test-deps doc/tags .luacheckcache /tags nvim.appimage -nvim-linux-x86_64* -nvim-macos* -nvim-win64* diff --git a/.luacheckrc b/.luacheckrc new file mode 100644 index 000000000..b0ee19d8a --- /dev/null +++ b/.luacheckrc @@ -0,0 +1,21 @@ +-- Rerun tests only if their modification time changed. +cache = true +codes = true + +exclude_files = { + "tests/indent/lua/" +} + +-- Glorious list of warnings: https://luacheck.readthedocs.io/en/stable/warnings.html +ignore = { + "212", -- Unused argument, In the case of callback function, _arg_name is easier to understand than _, so this option is set to off. + "411", -- Redefining a local variable. + "412", -- Redefining an argument. + "422", -- Shadowing an argument + "122" -- Indirectly setting a readonly global +} + +-- Global objects defined by the C code +read_globals = { + "vim", +} diff --git a/.luarc.json b/.luarc.json deleted file mode 100644 index 3917da0e2..000000000 --- a/.luarc.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json", - "runtime": { - "version": "LuaJIT" - }, - "workspace": { - "library": [ - "$VIMRUNTIME", - "${3rd}/busted/library" - ], - "ignoreDir": [ - ".test-deps", - "tests" - ], - "checkThirdParty": "Disable" - }, - "diagnostics": { - "groupFileStatus": { - "strict": "Opened", - "strong": "Opened" - }, - "groupSeverity": { - "strong": "Warning", - "strict": "Warning" - }, - "unusedLocalExclude": [ "_*" ] - } -} diff --git a/.stylua.toml b/.stylua.toml index a2b344750..ecb6dca5a 100644 --- a/.stylua.toml +++ b/.stylua.toml @@ -1,6 +1,6 @@ -column_width = 100 +column_width = 120 line_endings = "Unix" indent_type = "Spaces" indent_width = 2 -quote_style = "AutoPreferSingle" -call_parentheses = "Always" +quote_style = "AutoPreferDouble" +call_parentheses = "None" diff --git a/.tsqueryrc.json b/.tsqueryrc.json deleted file mode 100644 index d146e2f76..000000000 --- a/.tsqueryrc.json +++ /dev/null @@ -1,405 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/ribru17/ts_query_ls/refs/heads/master/schemas/config.json", - "parser_install_directories": ["${HOME}/.local/share/nvim/site/parser"], - "supported_abi_versions": { - "start": 13, - "end": 15 - }, - "parser_aliases": { - "html_tags": "html", - "ecma": "javascript", - "jsx": "javascript" - }, - "valid_captures": { - "highlights": { - "variable": "various variable names", - "variable.builtin": "built-in variable names (e.g. `this`)", - "variable.parameter": "parameters of a function", - "variable.parameter.builtin": "special parameters (e.g. `_`, `it`)", - "variable.member": "object and struct fields", - - "constant": "constant identifiers", - "constant.builtin": "built-in constant values", - "constant.macro": "constants defined by the preprocessor", - - "module": "modules or namespaces", - "module.builtin": "built-in modules or namespaces", - "label": "GOTO and other labels (e.g. `label:` in C), including heredoc labels", - - "string": "string literals", - "string.documentation": "string documenting code (e.g. Python docstrings)", - "string.regexp": "regular expressions", - "string.escape": "escape sequences", - "string.special": "other special strings (e.g. dates)", - "string.special.symbol": "symbols or atoms", - "string.special.url": "URIs (e.g. hyperlinks)", - "string.special.path": "filenames", - - "character": "character literals", - "character.special": "special characters (e.g. wildcards)", - - "boolean": "boolean literals", - "number": "numeric literals", - "number.float": "floating-point number literals", - - "type": "type or class definitions and annotations", - "type.builtin": "built-in types", - "type.definition": "identifiers in type definitions (e.g. `typedef ` in C)", - - "attribute": "attribute annotations (e.g. Python decorators, Rust lifetimes)", - "attribute.builtin": "builtin annotations (e.g. `@property` in Python)", - "property": "the key in key/value pairs", - - "function": "function definitions", - "function.builtin": "built-in functions", - "function.call": "function calls", - "function.macro": "preprocessor macros", - - "function.method": "method definitions", - "function.method.call": "method calls", - - "constructor": "constructor calls and definitions", - "operator": "symbolic operators (e.g. `+` / `*`)", - - "keyword": "keywords not fitting into specific categories", - "keyword.coroutine": "keywords related to coroutines (e.g. `go` in Go, `async/await` in Python)", - "keyword.function": "keywords that define a function (e.g. `func` in Go, `def` in Python)", - "keyword.operator": "operators that are English words (e.g. `and` / `or`)", - "keyword.import": "keywords for including or exporting modules (e.g. `import` / `from` in Python)", - "keyword.type": "keywords describing namespaces and composite types (e.g. `struct`, `enum`)", - "keyword.modifier": "keywords modifying other constructs (e.g. `const`, `static`, `public`)", - "keyword.repeat": "keywords related to loops (e.g. `for` / `while`)", - "keyword.return": "keywords like `return` and `yield`", - "keyword.debug": "keywords related to debugging", - "keyword.exception": "keywords related to exceptions (e.g. `throw` / `catch`)", - "keyword.conditional": "keywords related to conditionals (e.g. `if` / `else`)", - "keyword.conditional.ternary": "ternary operator (e.g. `?` / `:`)", - "keyword.directive": "various preprocessor directives & shebangs", - "keyword.directive.define": "preprocessor definition directives", - - "punctuation.delimiter": "delimiters (e.g. `;` / `.` / `,`)", - "punctuation.bracket": "brackets (e.g. `()` / `{}` / `[]`)", - "punctuation.special": "special symbols (e.g. `{}` in string interpolation)", - - "comment": "line and block comments", - "comment.documentation": "comments documenting code", - "comment.error": "error-type comments (e.g. `ERROR`, `FIXME`, `DEPRECATED`)", - "comment.warning": "warning-type comments (e.g. `WARNING`, `FIX`, `HACK`)", - "comment.todo": "todo-type comments (e.g. `TODO`, `WIP`)", - "comment.note": "note-type comments (e.g. `NOTE`, `INFO`, `XXX`)", - - "markup.strong": "bold text", - "markup.italic": "italic text", - "markup.strikethrough": "struck-through text", - "markup.underline": "underlined text (only for literal underline markup!)", - "markup.heading": "headings, titles (including markers)", - "markup.heading.1": "top-level heading", - "markup.heading.2": "section heading", - "markup.heading.3": "subsection heading", - "markup.heading.4": "and so on", - "markup.heading.5": "and so forth", - "markup.heading.6": "six levels ought to be enough for anybody", - "markup.quote": "block quotes", - "markup.math": "math environments (e.g. `$ ... $` in LaTeX)", - "markup.link": "text references, footnotes, citations, etc.", - "markup.link.label": "link, reference descriptions", - "markup.link.url": "URL-style links", - "markup.raw": "literal or verbatim text (e.g. inline code)", - "markup.raw.block": "literal or verbatim text as a stand-alone block ; (use priority 90 for blocks with injections)", - "markup.list": "list markers", - "markup.list.checked": "checked todo-style list markers", - "markup.list.unchecked": "unchecked todo-style list markers", - - "diff.plus": "added text (for diff files)", - "diff.minus": "deleted text (for diff files)", - "diff.delta": "changed text (for diff files)", - - "tag": "XML-style tag names (and similar)", - "tag.builtin": "builtin tag names (e.g. HTML5 tags)", - "tag.attribute": "XML-style tag attributes", - "tag.delimiter": "XML-style tag delimiters", - - "conceal": "captures that are only meant to be concealed", - "spell": "for defining regions to be spellchecked", - "nospell": "for defining regions that should NOT be spellchecked", - "none": "completely disable the highlight" - }, - "injections": { - "injection.content": "indicates that the captured node should have its contents re-parsed using another language", - "injection.language": "indicates that the captured node’s text may contain the name of a language that should be used to re-parse the `@injection.content`", - "injection.filename": "indicates that the captured node’s text may contain a filename; the corresponding filetype is then looked-up up via `vim.filetype.match()` and treated as the name of a language that should be used to re-parse the `@injection.content`" - }, - "folds": { - "fold": "fold this node" - }, - "indents": { - "indent.begin": "Specifies that the next line should be indented. Multiple indents on the same line get collapsed. Indent can also have `indent.immediate` set using a `#set!` directive, which permits the next line to indent even when the block intended to be indented has no content yet, improving interactive typing.", - "indent.end": "Used to specify that the indented region ends and any text subsequent to the capture should be dedented.", - "indent.align": "Specifies aligned indent blocks (like python aligned/hanging indent). Specify the delimiters with `indent.open_delimiter` and `indent.close_delimiter` metadata. For some languages, the last line of an `indent.align` block must not be the same indent as the natural next line, which can be controlled by setting `indent.avoid_last_matching_next`.", - "indent.dedent": "Specifies dedenting starting on the next line.", - "indent.branch": "Used to specify that a dedented region starts at the line including the captured nodes.", - "indent.ignore": "Specifies that indentation should be ignored for this node.", - "indent.auto": "Behaves like 'autoindent' buffer option.", - "indent.zero": "Sets indentation for this node to zero (no indentation)." - }, - "locals": { - "local.definition": "various definitions", - "local.definition.constant": "constants", - "local.definition.function": "functions", - "local.definition.method": "methods", - "local.definition.var": "variables", - "local.definition.parameter": "parameters", - "local.definition.macro": "preprocessor macros", - "local.definition.type": "types or classes", - "local.definition.field": "fields or properties", - "local.definition.enum": "enumerations", - "local.definition.namespace": "modules or namespaces", - "local.definition.import": "imported names", - "local.definition.associated": "the associated type of a variable", - "local.scope": "scope block", - "local.reference": "identifier reference" - } - }, - "valid_predicates": { - "eq": { - "any": true, - "parameters": [ - { - "type": "capture", - "arity": "required" - }, - { - "type": "any", - "arity": "required" - } - ], - "description": "checks for equality between two nodes, or a node and a string" - }, - "any-of": { - "parameters": [ - { - "type": "capture", - "arity": "required" - }, - { - "type": "string", - "arity": "required" - }, - { - "type": "string", - "arity": "required" - }, - { - "type": "string", - "arity": "variadic" - } - ], - "description": "match any of the given strings against the text corresponding to a node" - }, - "contains": { - "any": true, - "parameters": [ - { - "type": "capture", - "arity": "required" - }, - { - "type": "string", - "arity": "required" - }, - { - "type": "string", - "arity": "variadic" - } - ], - "description": "match a string against parts of the text corresponding to a node" - }, - "match": { - "any": true, - "parameters": [ - { - "type": "capture", - "arity": "required" - }, - { - "type": "string", - "arity": "required" - } - ], - "description": "Match a regexp against the text corresponding to a node" - }, - "lua-match": { - "any": true, - "parameters": [ - { - "type": "capture", - "arity": "required" - }, - { - "type": "string", - "arity": "required" - } - ], - "description": "match a Lua pattern against the text corresponding to a node" - }, - "has-ancestor": { - "parameters": [ - { - "type": "capture", - "arity": "required" - }, - { - "type": "string", - "arity": "required", - "constraint": "named_node" - }, - { - "type": "string", - "arity": "variadic", - "constraint": "named_node" - } - ], - "description": "match any of the given node types against all ancestors of a node" - }, - "has-parent": { - "parameters": [ - { - "type": "capture", - "arity": "required" - }, - { - "type": "string", - "arity": "required", - "constraint": "named_node" - }, - { - "type": "string", - "arity": "variadic", - "constraint": "named_node" - } - ], - "description": "match any of the given node types against the direct ancestor of a node" - }, - "kind-eq": { - "parameters": [ - { - "type": "capture", - "arity": "required" - }, - { - "type": "string", - "arity": "required", - "constraint": "named_node" - }, - { - "type": "string", - "arity": "variadic", - "constraint": "named_node" - } - ], - "description": "checks whether a capture corresponds to a given set of nodes" - } - }, - "valid_directives": { - "set": { - "parameters": [ - { - "type": "any", - "arity": "required" - }, - { - "type": "any", - "arity": "optional" - }, - { - "type": "any", - "arity": "optional" - } - ], - "description": "sets key/value metadata for a specific match or capture" - }, - "offset": { - "parameters": [ - { - "type": "capture", - "arity": "required" - }, - { - "type": "string", - "arity": "required", - "constraint": "integer" - }, - { - "type": "string", - "arity": "required", - "constraint": "integer" - }, - { - "type": "string", - "arity": "required", - "constraint": "integer" - }, - { - "type": "string", - "arity": "required", - "constraint": "integer" - } - ], - "description": "Takes the range of the captured node and applies an offset. This will set a new range in the form of a list like { {start_row}, {start_col}, {end_row}, {end_col} } for the captured node with `capture_id` as `metadata[capture_id].range`." - }, - "gsub": { - "parameters": [ - { - "type": "capture", - "arity": "required" - }, - { - "type": "string", - "arity": "required" - }, - { - "type": "string", - "arity": "required" - } - ], - "description": "Transforms the content of the node using a Lua pattern. This will set a new `metadata[capture_id].text`." - }, - "trim": { - "parameters": [ - { - "type": "capture", - "arity": "required" - }, - { - "type": "string", - "arity": "optional", - "constraint": { - "enum": ["0", "1"] - } - }, - { - "type": "string", - "arity": "optional", - "constraint": { - "enum": ["0", "1"] - } - }, - { - "type": "string", - "arity": "optional", - "constraint": { - "enum": ["0", "1"] - } - }, - { - "type": "string", - "arity": "optional", - "constraint": { - "enum": ["0", "1"] - } - } - ], - "description": "Trims whitespace from the node. Sets a new `metadata[capture_id].range`. Takes a capture ID and, optionally, four integers to customize trimming behavior (`1` meaning trim, `0` meaning don't trim). When only given a capture ID, trims blank lines (lines that contain only whitespace, or are empty) from the end of the node (for backwards compatibility). Can trim all whitespace from both sides of the node if parameters are given." - } - } -} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52ec52633..9e104f252 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,103 +1,78 @@ # Contributing to `nvim-treesitter` -The main parts of `nvim-treesitter` are -* a curated list of [parsers](#Parsers); -* a collection of [queries](#Queries). +First of all, thank you very much for contributing to `nvim-treesitter`. -Before describing these in detail, some general advice: -* Some basic knowledge of how tree-sitter works is assumed; we recommend reading - - the [upstream documentation](https://tree-sitter.github.io/tree-sitter/); - - [Neovim's documentation](https://neovim.io/doc/user/treesitter.html#treesitter). -* There are dedicated Matrix channels for questions and general help: - - [#nvim-treesitter](https://matrix.to/#/#nvim-treesitter:matrix.org) for questions specific to Neovim's implementation and the queries here; - - [#tree-sitter](https://matrix.to/#/#tree-sitter-chat:matrix.org) for general questions regarding treesitter queries and the `tree-sitter` CLI. +If you haven't already, you should really come and reach out to us on our [Zulip] +server, so we can help you with any question you might have! +There is also a [Matrix channel] for tree-sitter support in Neovim. -## Parsers +As you know, `nvim-treesitter` is roughly split in two parts: ->[!IMPORTANT] -> To qualify for inclusion, a parser must meet the following criteria: -> * correspond to a filetype detected by Neovim (nightly) -> * feature complete, tested by users, and actively maintained (according to maintainer discretion) -> * hosted or mirrored on Github (other codeforges are not reliable enough for CI) -> * covered by CI using [upstream workflows](https://github.com/tree-sitter/workflows) -> * provide reference queries covered by a [`ts_query_ls` workflow](https://github.com/tree-sitter-grammars/template/blob/9c46d09d688d27c7aef31c2b32f50260de4e7906/.github/workflows/ci.yml#L69-L86) -> * if the repo contains a `src/parser.c`, it must support the latest ABI -> * if the repo does _not_ contain a `src/parser.c`, it must contain an up-to-date `src/grammar.json` -> * if the repo contains an external scanner, it must be written in C99 -> -> Tier 1 parsers (preferred) in addition need to -> * make regular releases following semver (_patch_ for fixes not affecting queries; _minor_ for changes introducing new nodes or patterns; _major_ for changes removing nodes or previously valid patterns) -> * provide WASM release artifacts +- Parser configurations : for various things like `locals`, `highlights` +- What we like to call *modules* : tiny lua modules that provide a given feature, based on parser configurations -To add a new parser, edit the following files: +Depending on which part of the plugin you want to contribute to, please read the appropriate section. -1. In `lua/parsers.lua`, add an entry to the returned table of the following form: +## Style Checks and Tests -```lua -zimbu = { - install_info = { - url = 'https://github.com/zimbulang/tree-sitter-zimbu', -- git repo; use `path` for local path - revision = 'v2.1', -- tag or commit hash - -- optional entries: - branch = 'develop', -- only needed if different from default branch - location = 'parser', -- only needed if the parser is in subdirectory of a "monorepo" - generate = true, -- only needed if repo does not contain pre-generated src/parser.c - }, - maintainers = { '@me' }, -- the _query_ maintainers - tier = 1, -- stable: track versioned releases instead of latest commit - -- optional entries: - requires = { 'vim' }, -- if the queries inherit from another language - readme_note = "an example language", -} +We haven't implemented any functional tests yet. Feel free to contribute. +However, we check code style with `luacheck` and `stylua`! +Please install luacheck and activate our `pre-push` hook to automatically check style before +every push: + +```bash +luarocks install luacheck +cargo install stylua +ln -s ../../scripts/pre-push .git/hooks/pre-push ``` ->[!IMPORTANT] -> The "maintainers" here refers to the person maintaining the **queries** in `nvim-treesitter`, not the parser maintainers (who likely don't use Neovim). The maintainers' duty is to review issues and PRs related to the query and to keep them updated with respect to parser changes. +## Adding new modules -2. If the parser name is not the same as the Vim filetype, add an entry to the `filetypes` table in `plugin/filetypes.lua`: +If you want to see a new functionality added to `nvim-treesitter` feel free to first open an issue +to that we can track our solution! +Thus far, there is basically two types of modules: -```lua - zimbu = { 'zu' }, -``` +- Little modules (like `incremental selection`) that are built in `nvim-treesitter`, we call them + `builtin modules`. +- Bigger modules (like `completion-treesitter`, or `nvim-tree-docs`), or modules that integrate + with other plugins, that we call `remote modules`. -3. Update the list of [supported languages] by running `make docs` (or `./scripts/update-readme.lua` if on Windows). +In any case, you can build your own module ! To help you started in the process, we have a template +repository designed to build new modules [here](https://github.com/nvim-treesitter/module-template). +Feel free to use it, and contact us over on our +[Zulip] or on the "Neovim tree-sitter" [Matrix channel]. -4. Test if both `:TSInstall zimbu` and `:TSInstallFromGrammar zimbu` work without errors (`:checkhealth treesitter` or `./scripts/check-parsers.lua zimbu`). +## Parser configurations ->[!IMPORTANT] -> You also need to add queries in order for the parser to actually be useful! +Contributing to parser configurations is basically modifying one of the `queries/*/*.scm`. +Each of these `scheme` files contains a *tree-sitter query* for a given purpose. +Before going any further, we highly suggest that you [read more about tree-sitter queries](https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries). -When you're done, open a Pull Request using the [provided template](.github/PULL_REQUEST_TEMPLATE/new_language.md), e.g. using `gh pr create -B main -T new_language`. +Each query has an appropriate name, which is then used by modules to extract data from the syntax tree. +For now these are the types of queries used by `nvim-treesitter`: -## Queries +- `highlights.scm`: used for syntax highlighting, using the `highlight` module. +- `locals.scm`: used to extract keyword definitions, scopes, references, etc, using the `locals` module. +- `textobjects.scm`: used to define text objects. +- `folds.scm`: used to define folds. +- `injections.scm`: used to define injections. -To add (or edit existing) queries, create a corresponding `runtime/queries/zimbu/*.scm` file: +For these types there is a *norm* you will have to follow so that features work fine. +Here are some global advices : -- `highlights.scm` used for syntax highlighting, -- `injections.scm` used to specify nodes whose content should be parsed as a different language; -- `folds.scm`; used to define folds; -- `locals.scm`: used to extract keyword definitions, scopes, references, etc. (not used in this plugin). -- `indents.scm`; used to control indentation. - -See [tree-sitter queries] for a basic description of the query language. The following tools can be helpful when writing or editing queries: -* [ts_query_ls] is a language server for treesitter queries, which can validate, autocomplete, and format. This tool can also be used as an offline linter and formatter (accessible through `make lintquery`, `make checkquery`, `make formatquery` targets). -* Neovim's `:InspectTree` will show the parsed tree for a buffer and highlight the text corresponding to any given node (and vice versa). -* `:EditQuery` opens a "playground" where you can write query patterns and see which parts of the buffer are captured by each capture. - ->[!IMPORTANT] -> The valid captures that can be used in queries is different for each editor, so you cannot just copy them, e.g., from Helix or the parser repositories. For Neovim, all valid captures are listed below. You can verify that your changes adhere to this by running `make lintquery`. - ->[!IMPORTANT] -> Since grammars can change constantly, it is important to make sure that the patterns in a query are actually valid for the parser specified in nvim-treesitter's manifest. This can be verified using `make checkquery` (which requires the parser to be installed in the default directory(!) through `nvim-treesitter`). Opening the query in Neovim with the parser installed will also show all invalid patterns, either via [ts_query_ls] or Neovim's builtin query-linter. - ->[!TIP] -> Before opening a PR, run `make query` to format, lint, and check all queries. - -#### Inheriting languages +- If your language is listed [here](https://github.com/nvim-treesitter/nvim-treesitter#supported-languages), + you can install the [playground plugin](https://github.com/nvim-treesitter/playground). +- If your language is listed [here](https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries), + you can debug and experiment with your queries there. +- If not, you should consider installing the [tree-sitter cli](https://github.com/tree-sitter/tree-sitter/tree/master/cli), + you should then be able to open a local playground using `tree-sitter build-wasm && tree-sitter web-ui` within the + parsers repo. +- Examples of queries can be found in [queries/](queries/) +- Matches in the bottom will override queries that are above of them. If your language is an extension of a language (TypeScript is an extension of JavaScript for example), you can include the queries from your base language by adding the following _as the first -line of your file_: +line of your file_. ```query ; inherits: lang1,(optionallang) @@ -106,409 +81,186 @@ line of your file_: If you want to inherit a language, but don't want the languages inheriting from yours to inherit it, you can mark the language as optional (by putting it between parenthesis). -#### Formatting - -All queries are expected to follow a standard format, with every node on a single line and indented by two spaces for each level of nesting. You can automatically format the bundled queries by running `make formatquery`. - -Should you need to preserve a specific format for a node, you can exempt it (and all contained nodes) by placing before it -```query -; format-ignore -``` - ### Highlights -Syntax highlighting is specified in a `highlights.scm` query, which assigns treesitter nodes to captures that can be assigned a highlight group. This feature is implemented in Neovim and documented at [`:h treesitter-highlight`](https://neovim.io/doc/user/treesitter.html#treesitter-highlight). -Note that your color scheme needs to define (or link) these captures as highlight groups. You can use Neovim's built-in `:Inspect` function to see exactly which highlight groups are applied at a given position. +As languages differ quite a lot, here is a set of captures available to you when building a `highlights.scm` query. +One important thing to note is that many of these capture groups are not supported by `neovim` for now, and will not have any +effect on highlighting. We will work on improving highlighting in the near future though. -The valid captures are listed below. +#### Misc -#### Identifiers - -```query -@variable ; various variable names -@variable.builtin ; built-in variable names (e.g. `this`) -@variable.parameter ; parameters of a function -@variable.parameter.builtin ; special parameters (e.g. `_`, `it`) -@variable.member ; object and struct fields - -@constant ; constant identifiers -@constant.builtin ; built-in constant values -@constant.macro ; constants defined by the preprocessor - -@module ; modules or namespaces -@module.builtin ; built-in modules or namespaces -@label ; GOTO and other labels (e.g. `label:` in C), including heredoc labels -``` - -#### Literals - -```query -@string ; string literals -@string.documentation ; string documenting code (e.g. Python docstrings) -@string.regexp ; regular expressions -@string.escape ; escape sequences -@string.special ; other special strings (e.g. dates) -@string.special.symbol ; symbols or atoms -@string.special.url ; URIs (e.g. hyperlinks) -@string.special.path ; filenames - -@character ; character literals -@character.special ; special characters (e.g. wildcards) - -@boolean ; boolean literals -@number ; numeric literals -@number.float ; floating-point number literals -``` - -#### Types - -```query -@type ; type or class definitions and annotations -@type.builtin ; built-in types -@type.definition ; identifiers in type definitions (e.g. `typedef ` in C) - -@attribute ; attribute annotations (e.g. Python decorators, Rust lifetimes) -@attribute.builtin ; builtin annotations (e.g. `@property` in Python) -@property ; the key in key/value pairs -``` - -#### Functions - -```query -@function ; function definitions -@function.builtin ; built-in functions -@function.call ; function calls -@function.macro ; preprocessor macros - -@function.method ; method definitions -@function.method.call ; method calls - -@constructor ; constructor calls and definitions -@operator ; symbolic operators (e.g. `+` / `*`) -``` - -#### Keywords - -```query -@keyword ; keywords not fitting into specific categories -@keyword.coroutine ; keywords related to coroutines (e.g. `go` in Go, `async/await` in Python) -@keyword.function ; keywords that define a function (e.g. `func` in Go, `def` in Python) -@keyword.operator ; operators that are English words (e.g. `and` / `or`) -@keyword.import ; keywords for including or exporting modules (e.g. `import` / `from` in Python) -@keyword.type ; keywords describing namespaces and composite types (e.g. `struct`, `enum`) -@keyword.modifier ; keywords modifying other constructs (e.g. `const`, `static`, `public`) -@keyword.repeat ; keywords related to loops (e.g. `for` / `while`) -@keyword.return ; keywords like `return` and `yield` -@keyword.debug ; keywords related to debugging -@keyword.exception ; keywords related to exceptions (e.g. `throw` / `catch`) - -@keyword.conditional ; keywords related to conditionals (e.g. `if` / `else`) -@keyword.conditional.ternary ; ternary operator (e.g. `?` / `:`) - -@keyword.directive ; various preprocessor directives & shebangs -@keyword.directive.define ; preprocessor definition directives +```scheme +@comment ; line and block comments +@error ; syntax/parser errors +@none ; completely disable the highlight +@preproc ; various preprocessor directives & shebangs +@define ; preprocessor definition directives +@operator ; symbolic operators (e.g. `+` / `*`) ``` #### Punctuation -```query +```scheme @punctuation.delimiter ; delimiters (e.g. `;` / `.` / `,`) @punctuation.bracket ; brackets (e.g. `()` / `{}` / `[]`) @punctuation.special ; special symbols (e.g. `{}` in string interpolation) ``` -#### Comments +#### Literals -```query -@comment ; line and block comments -@comment.documentation ; comments documenting code +```scheme +@string ; string literals +@string.regex ; regular expressions +@string.escape ; escape sequences +@string.special ; other special strings (e.g. dates) -@comment.error ; error-type comments (e.g. `ERROR`, `FIXME`, `DEPRECATED`) -@comment.warning ; warning-type comments (e.g. `WARNING`, `FIX`, `HACK`) -@comment.todo ; todo-type comments (e.g. `TODO`, `WIP`) -@comment.note ; note-type comments (e.g. `NOTE`, `INFO`, `XXX`) +@character ; character literals +@character.special ; special characters (e.g. wildcards) + +@boolean ; boolean literals +@number ; numeric literals +@float ; floating-point number literals ``` -#### Markup +#### Functions + +```scheme +@function ; function definitions +@function.builtin ; built-in functions +@function.call ; function calls +@function.macro ; preprocessor macros + +@method ; method definitions +@method.call ; method calls + +@constructor ; constructor calls and definitions +@parameter ; parameters of a function +``` + +#### Keywords + +```scheme +@keyword ; various keywords +@keyword.function ; keywords that define a function (e.g. `func` in Go, `def` in Python) +@keyword.operator ; operators that are English words (e.g. `and` / `or`) +@keyword.return ; keywords like `return` and `yield` + +@conditional ; keywords related to conditionals (e.g. `if` / `else`) +@conditional.ternary ; Ternary operator: condition ? 1 : 2 +@repeat ; keywords related to loops (e.g. `for` / `while`) +@debug ; keywords related to debugging +@label ; GOTO and other labels (e.g. `label:` in C) +@include ; keywords for including modules (e.g. `import` / `from` in Python) +@exception ; keywords related to exceptions (e.g. `throw` / `catch`) +``` + +#### Types + +```scheme +@type ; type or class definitions and annotations +@type.builtin ; built-in types +@type.definition ; type definitions (e.g. `typedef` in C) +@type.qualifier ; type qualifiers (e.g. `const`) + +@storageclass ; visibility/life-time modifiers +@attribute ; attribute annotations (e.g. Python decorators) +@field ; object and struct fields +@property ; similar to `@field` +``` + +#### Identifiers + +```scheme +@variable ; various variable names +@variable.builtin ; built-in variable names (e.g. `this`) + +@constant ; constant identifiers +@constant.builtin ; built-in constant values +@constant.macro ; constants defined by the preprocessor + +@namespace ; modules or namespaces +@symbol ; symbols or atoms +``` + +#### Text Mainly for markup languages. -```query -@markup.strong ; bold text -@markup.italic ; italic text -@markup.strikethrough ; struck-through text -@markup.underline ; underlined text (only for literal underline markup!) +```scheme +@text ; non-structured text +@text.strong ; bold text +@text.emphasis ; text with emphasis +@text.underline ; underlined text +@text.strike ; strikethrough text +@text.title ; text that is part of a title +@text.literal ; literal or verbatim text +@text.uri ; URIs (e.g. hyperlinks) +@text.math ; math environments (e.g. `$ ... $` in LaTeX) +@text.environment ; text environments of markup languages +@text.environment.name ; text indicating the type of an environment +@text.reference ; text references, footnotes, citations, etc. -@markup.heading ; headings, titles (including markers) -@markup.heading.1 ; top-level heading -@markup.heading.2 ; section heading -@markup.heading.3 ; subsection heading -@markup.heading.4 ; and so on -@markup.heading.5 ; and so forth -@markup.heading.6 ; six levels ought to be enough for anybody +@text.todo ; todo notes +@text.note ; info notes +@text.warning ; warning notes +@text.danger ; danger/error notes -@markup.quote ; block quotes -@markup.math ; math environments (e.g. `$ ... $` in LaTeX) - -@markup.link ; text references, footnotes, citations, etc. -@markup.link.label ; link, reference descriptions -@markup.link.url ; URL-style links - -@markup.raw ; literal or verbatim text (e.g. inline code) -@markup.raw.block ; literal or verbatim text as a stand-alone block - ; (use priority 90 for blocks with injections) - -@markup.list ; list markers -@markup.list.checked ; checked todo-style list markers -@markup.list.unchecked ; unchecked todo-style list markers +@text.diff.add ; added text (for diff files) +@text.diff.delete ; deleted text (for diff files) ``` -```query -@diff.plus ; added text (for diff files) -@diff.minus ; deleted text (for diff files) -@diff.delta ; changed text (for diff files) +#### Tags + +Used for XML-like tags. + +```scheme +@tag ; XML tag names +@tag.attribute ; XML tag attributes +@tag.delimiter ; XML tag delimiters ``` -```query -@tag ; XML-style tag names (and similar) -@tag.builtin ; builtin tag names (e.g. HTML5 tags) -@tag.attribute ; XML-style tag attributes -@tag.delimiter ; XML-style tag delimiters +#### Conceal + + +```scheme +@conceal ; for captures that are only used for concealing ``` -#### Non-highlighting captures +`@conceal` must be followed by `(#set! conceal "")`. -```query -@conceal ; captures that are only meant to be concealed -``` +#### Spell ->[!TIP] -> * See [`:h tree-sitter-highlight-conceal`](https://neovim.io/doc/user/treesitter.html#treesitter-highlight-conceal). -> * The capture should be meaningful to allow proper highlighting when `set conceallevel=0`. -> * A conceal can be restricted to part of the capture via the [`#offset!` directive](https://neovim.io/doc/user/treesitter.html#treesitter-directive-offset%21). - -```query +```scheme @spell ; for defining regions to be spellchecked @nospell ; for defining regions that should NOT be spellchecked ``` ->[!TIP] -> The main types of nodes that should be spell checked are -> - comments -> - strings; where it makes sense. Strings that have interpolation or are typically used for non text purposes are not spell checked (e.g. bash). - -#### Predicates - -Captures can be restricted according to node contents using [predicates](https://neovim.io/doc/user/treesitter.html#treesitter-predicates). - ->[!IMPORTANT] -> For performance reasons, prefer earlier predicates in this list: -> -> 1. `#eq?` (literal match) -> 2. `#any-of?` (one of several literal matches) -> 3. `#lua-match?` (match against a [Lua pattern](https://neovim.io/doc/user/luaref.html#lua-pattern)) -> 4. `#match?`/`#vim-match?` (match against a [Vim regular expression](https://neovim.io/doc/user/pattern.html#regexp) - -Besides those provided by Neovim, nvim-treesitter also implements - -```query -#kind-eq? ; checks whether a capture corresponds to a given set of nodes -#any-kind-eq? ; checks whether any of a list of captures corresponds to a given set of nodes -``` - -#### Directives - -Nodes contain metadata that can be modified via [directives](https://neovim.io/doc/user/treesitter.html#treesitter-directives). - -#### Priority - -Captures can be assigned a priority to control precedence of highlights via the -`#set! priority ` directive (see [`:h treesitter-highlight-priority`](https://neovim.io/doc/user/treesitter.html#treesitter-highlight-priority)). This is useful for controlling conflicts with injected languages or when inheriting queries from other languages. - ->[!NOTE] -> The default priority for treesitter highlights is `100`; queries should only -set priorities between `90` and `120`, to avoid conflict with other sources of highlighting (such as diagnostics or LSP semantic tokens). - ->[!TIP] -> Precedence is also influenced by pattern order in a query file. If possible, try to achieve the correct result by reordering patterns before resorting to explicit priorities. - -### Injections - -Language injections are controlled by `injections.scm` queries, which specify nodes that should be parsed as a different language. This feature is implemented in Neovim and documented at -[`:h treesitter-language-injections](https://neovim.io/doc/user/treesitter.html#treesitter-language-injections). - -The valid captures are: - -```query -@injection.language ; dynamic detection of the injection language (i.e. the text of the captured node describes the language) -@injection.content ; region for the dynamically detected language -@injection.filename ; indicates that the captured node’s text may contain a filename; the corresponding filetype is then looked-up up via vim.filetype.match() and treated as the name of a language that should be used to re-parse the `@injection.content` -``` - ->[!TIP] -> When writing injection queries, try to ensure that each captured node is only matched by a single pattern. - -### Folds - -You can define folds for a given language by adding a `folds.scm` query. This is implemented in Neovim. The only valid capture is `@fold`: - -```query -(function_definition) @fold ; fold this node -``` - -Folds should be given to nodes with defined start and end delimiters/patterns, or to consecutive nodes which are part of the same conceptual "grouping", such as consecutive line comments or import statements. The following items are valid fold candidates: - -- Function/method definitions -- Class/interface/trait definitions -- Switch/match statements, and individual match arms -- Execution blocks (such as those found in conditional statements or loops) -- Parameter/argument lists -- Array/object/string expressions -- Consecutive import statements, consecutive line comments - -The following items would *not* be valid fold candidates: - -- Multiline assignment statements -- Multiline property access expressions - -As a rule of thumb, these highlight captures usually reside in or around objects which should be folded: - -- `@function`, `@function.method` -- `@keyword.import`, `@keyword.conditional`, `@keyword.repeat` -- `@comment`, `@comment.documentation` -- `@string`, `@string.documentation` -- `@markup.heading.x`, `@markup.list` - -### Indents - ->[!WARNING] -> Treesitter-based indentation is still experimental and likely to have breaking changes in the future. - -Indentation for a language is controlled by `indents.scm` queries. The following captures can be used to set the indentation for nodes, either relative or absolute - -* `@indent.begin` specifies that the next line should be indented. Multiple -indents on the same line get collapsed, e.g., -```query - ( - (if_statement) - (ERROR "else") @indent.begin - ) -``` -You can also `#set! indent.immediate` to permit the next line to indent even when the block intended to be indented has no content yet. (This can improve interactive typing.) -For example for Python, -```query - ((if_statement) @indent.begin - (#set! indent.immediate 1)) -``` -will allow -```python - if True: - # Auto indent to here -``` - -* `@indent.end` is used to specify that the indented region ends and any text subsequent to the capture should be dedented. - -* `@indent.branch` is used to specify that a dedented region starts at the line _including_ the captured nodes. - -* `@indent.dedent` specifies dedenting starting on the _next_ line. - -* `@indent.auto` behaves like Vim's [`autoindent`](https://neovim.io/doc/user/options.html#'autoindent') buffer option (copy whatever the indentation of previous line is when opening a new line after it). - -* `@indent.ignore` specifies that no indent should be added to this node. - -* `@indent.zero` sets the indentation of this node to 0 (i.e., removes _all_ indentation). - -* `@indent.align` can be used to specify blocks that should have the same indentation. -This allows -``` - foo(a, - b, - c) -``` -as well as -``` - foo( - a, - b, - c) -``` -and -``` - foo( - a, - b, - c - ) -``` -To specify the delimiters to align at, `#set! indent.open_delimiter` and -`indent.close_delimiter`, e.g., -```query - ((argument_list) @indent.align - (#set! indent.open_delimiter "(") - (#set! indent.close_delimiter ")")) -``` -For some languages, the last line of an `indent.align` block must not be -the same indent as the natural next line. -For example in Python, - -```python - if (a > b and - c < d): - pass -``` -is not correct, whereas -```python - if (a > b and - c < d): - pass -``` -would be correctly indented. This behavior may be selected by setting -`indent.avoid_last_matching_next`. For example, -```query - (if_statement - condition: (parenthesized_expression) @indent.align - (#set! indent.open_delimiter "(") - (#set! indent.close_delimiter ")") - (#set! indent.avoid_last_matching_next 1) - ) -``` -specifies that the last line of an `@indent.align` capture -should be additionally indented to avoid clashing with the indent of the first -line of the block inside an `if`. - ### Locals -Locals are used to keep track of definitions and references in local or global -scopes, see [upstream -documentation](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#local-variables). -Note that nvim-treesitter uses more specific subcaptures for definitions and -**does not use locals** (for highlighting or any other purpose). These queries -are only provided for limited backwards compatibility. +```scheme +@definition ; various definitions +@definition.constant ; constants +@definition.function ; functions +@definition.method ; methods +@definition.var ; variables +@definition.parameter ; parameters +@definition.macro ; preprocessor macros +@definition.type ; types or classes +@definition.field ; fields or properties +@definition.enum ; enumerations +@definition.namespace ; modules or namespaces +@definition.import ; imported names +@definition.associated ; the associated type of a variable -```query -@local.definition ; various definitions -@local.definition.constant ; constants -@local.definition.function ; functions -@local.definition.method ; methods -@local.definition.var ; variables -@local.definition.parameter ; parameters -@local.definition.macro ; preprocessor macros -@local.definition.type ; types or classes -@local.definition.field ; fields or properties -@local.definition.enum ; enumerations -@local.definition.namespace ; modules or namespaces -@local.definition.import ; imported names -@local.definition.associated ; the associated type of a variable - -@local.scope ; scope block -@local.reference ; identifier reference +@scope ; scope block +@reference ; identifier reference ``` -#### Definition scope +#### Definition Scope You can set the scope of a definition by setting the `scope` property on the definition. -For example, a JavaScript function declaration creates a scope. The function name is captured as the definition. +For example, a javascript function declaration creates a scope. The function name is captured as the definition. This means that the function definition would only be available WITHIN the scope of the function, which is not the case. The definition can be used in the scope the function was defined in. @@ -520,8 +272,8 @@ doSomething(); // Should point to the declaration as the definition ```query (function_declaration - ((identifier) @local.definition.var) - (#set! definition.var.scope "parent")) + ((identifier) @definition.var) + (#set! "definition.var.scope" "parent")) ``` Possible scope values are: @@ -530,7 +282,45 @@ Possible scope values are: - `global`: The definition is valid in the root scope - `local`: The definition is valid in the containing scope. This is the default behavior +### Folds -[supported languages]: https://github.com/nvim-treesitter/nvim-treesitter/SUPPORTED_LANGUAGES.md -[tree-sitter queries]: https://tree-sitter.github.io/tree-sitter/using-parsers/queries/index.html -[ts_query_ls]: https://github.com/ribru17/ts_query_ls +You can define folds for a given language by adding a `folds.scm` query : + +```scheme +@fold ; fold this node +``` + +If the `folds.scm` query is not present, this will fall back to the `@scope` captures in the `locals` +query. + +### Injections + +Some captures are related to language injection (like markdown code blocks). They are used in `injections.scm`. +You can directly use the name of the language that you want to inject (e.g. `@html` to inject html). + +If you want to dynamically detect the language (e.g. for Markdown blocks) use the `@language` to capture +the node describing the language and `@content` to describe the injection region. + +```scheme +@{lang} ; e.g. @html to describe a html region + +@language ; dynamic detection of the injection language (i.e. the text of the captured node describes the language) +@content ; region for the dynamically detected language +@combined ; combine all matches of a pattern as one single block of content +``` + +### Indents + +```scheme +@indent ; indent children when matching this node +@indent_end ; marks the end of indented block +@aligned_indent ; behaves like python aligned/hanging indent +@dedent ; dedent children when matching this node +@branch ; dedent itself when matching this node +@ignore ; do not indent in this node +@auto ; behaves like 'autoindent' buffer option +@zero_indent ; sets this node at position 0 (no indent) +``` + +[Zulip]: https://nvim-treesitter.zulipchat.com +[Matrix channel]: https://matrix.to/#/#nvim-treesitter:matrix.org diff --git a/Makefile b/Makefile deleted file mode 100644 index e22e2e6ab..000000000 --- a/Makefile +++ /dev/null @@ -1,139 +0,0 @@ -NVIM_VERSION ?= nightly - -DEPDIR ?= .test-deps -CURL ?= curl -sL --create-dirs - -ifeq ($(shell uname -s),Darwin) - NVIM_ARCH ?= macos-arm64 - LUALS_ARCH ?= darwin-arm64 - STYLUA_ARCH ?= macos-aarch64 - RUST_ARCH ?= aarch64-apple-darwin -else - NVIM_ARCH ?= linux-x86_64 - LUALS_ARCH ?= linux-x64 - STYLUA_ARCH ?= linux-x86_64 - RUST_ARCH ?= x86_64-unknown-linux-gnu -endif - -.DEFAULT_GOAL := all - -# download test dependencies - -NVIM := $(DEPDIR)/nvim-$(NVIM_ARCH) -NVIM_TARBALL := $(NVIM).tar.gz -NVIM_URL := https://github.com/neovim/neovim/releases/download/$(NVIM_VERSION)/$(notdir $(NVIM_TARBALL)) -NVIM_BIN := $(NVIM)/nvim-$(NVIM_ARCH)/bin/nvim -NVIM_RUNTIME=$(NVIM)/nvim-$(NVIM_ARCH)/share/nvim/runtime - -.PHONY: nvim -nvim: $(NVIM) - -$(NVIM): - $(CURL) $(NVIM_URL) -o $(NVIM_TARBALL) - mkdir $@ - tar -xf $(NVIM_TARBALL) -C $@ - rm -rf $(NVIM_TARBALL) - -EMMYLUALS := $(DEPDIR)/emmylua_check-$(LUALS_ARCH) -EMMYLUALS_TARBALL := $(EMMYLUALS).tar.gz -EMMYLUALS_URL := https://github.com/emmyluals/emmylua-analyzer-rust/releases/latest/download/$(notdir $(EMMYLUALS_TARBALL)) - -.PHONY: emmyluals -emmyluals: $(EMMYLUALS) - -$(EMMYLUALS): - $(CURL) $(EMMYLUALS_URL) -o $(EMMYLUALS_TARBALL) - mkdir $@ - tar -xf $(EMMYLUALS_TARBALL) -C $@ - rm -rf $(EMMYLUALS_TARBALL) - -STYLUA := $(DEPDIR)/stylua-$(STYLUA_ARCH) -STYLUA_TARBALL := $(STYLUA).zip -STYLUA_URL := https://github.com/JohnnyMorganz/StyLua/releases/latest/download/$(notdir $(STYLUA_TARBALL)) - -.PHONY: stylua -stylua: $(STYLUA) - -$(STYLUA): - $(CURL) $(STYLUA_URL) -o $(STYLUA_TARBALL) - unzip $(STYLUA_TARBALL) -d $(STYLUA) - rm -rf $(STYLUA_TARBALL) - -TSQUERYLS := $(DEPDIR)/ts_query_ls-$(RUST_ARCH) -TSQUERYLS_TARBALL := $(TSQUERYLS).tar.gz -TSQUERYLS_URL := https://github.com/ribru17/ts_query_ls/releases/latest/download/$(notdir $(TSQUERYLS_TARBALL)) - -.PHONY: tsqueryls -tsqueryls: $(TSQUERYLS) - -$(TSQUERYLS): - $(CURL) $(TSQUERYLS_URL) -o $(TSQUERYLS_TARBALL) - mkdir $@ - tar -xf $(TSQUERYLS_TARBALL) -C $@ - rm -rf $(TSQUERYLS_TARBALL) - -HLASSERT := $(DEPDIR)/highlight-assertions-$(RUST_ARCH) -HLASSERT_TARBALL := $(HLASSERT).tar.gz -HLASSERT_URL := https://github.com/nvim-treesitter/highlight-assertions/releases/latest/download/$(notdir $(HLASSERT_TARBALL)) - -.PHONY: hlassert -hlassert: $(HLASSERT) - -$(HLASSERT): - $(CURL) $(HLASSERT_URL) -o $(HLASSERT_TARBALL) - mkdir $@ - tar -xf $(HLASSERT_TARBALL) -C $@ - rm -rf $(HLASSERT_TARBALL) - -PLENTEST := $(DEPDIR)/plentest.nvim - -.PHONY: plentest -plentest: $(PLENTEST) - -$(PLENTEST): - git clone --filter=blob:none https://github.com/nvim-treesitter/plentest.nvim $(PLENTEST) - -# actual test targets - -.PHONY: lua -lua: formatlua checklua - -.PHONY: formatlua -formatlua: $(STYLUA) - $(STYLUA)/stylua . - -.PHONY: checklua -checklua: $(EMMYLUALS) $(NVIM) - VIMRUNTIME=$(NVIM_RUNTIME) $(EMMYLUALS)/emmylua_check --warnings-as-errors . - -.PHONY: query -query: formatquery lintquery checkquery - -.PHONY: lintquery -lintquery: $(TSQUERYLS) - $(TSQUERYLS)/ts_query_ls lint runtime/queries - -.PHONY: formatquery -formatquery: $(TSQUERYLS) - $(TSQUERYLS)/ts_query_ls format runtime/queries - -.PHONY: checkquery -checkquery: $(TSQUERYLS) - $(TSQUERYLS)/ts_query_ls check runtime/queries - -.PHONY: docs -docs: $(NVIM) - $(NVIM_BIN) -l scripts/update-readme.lua - -.PHONY: tests -tests: $(NVIM) $(HLASSERT) $(PLENTEST) - HLASSERT=$(HLASSERT)/highlight-assertions PLENTEST=$(PLENTEST) \ - $(NVIM_BIN) --headless --clean -u scripts/minimal_init.lua \ - -c "lua require('plentest').test_directory('tests/$(TESTS)', { minimal_init = './scripts/minimal_init.lua' })" - -.PHONY: all -all: lua query docs tests - -.PHONY: clean -clean: - rm -rf $(DEPDIR) diff --git a/README.md b/README.md index 235df2dc3..a3db5d966 100644 --- a/README.md +++ b/README.md @@ -1,187 +1,654 @@ -

- nvim-treesitter -

+
+

nvim-treesitter

+

+ + Zulip Chat + + + Linting and Style + + + Syntax files + +

+
-The `nvim-treesitter` plugin provides -1. functions for installing, updating, and removing [**tree-sitter parsers**](SUPPORTED_LANGUAGES.md); -2. a collection of **queries** for enabling tree-sitter features built into Neovim for these languages; -3. a staging ground for [treesitter-based features](#Supported-features) considered for upstreaming to Neovim. +
+

+ Logo +

+

+ Treesitter + configurations and abstraction layer for + Neovim. +

+

+ + Logo by @steelsojka + +

+
-For details on these and how to help improving them, see [CONTRIBUTING.md](./CONTRIBUTING.md). +The goal of `nvim-treesitter` is both to provide a simple and easy way to use the interface for [tree-sitter](https://github.com/tree-sitter/tree-sitter) in Neovim and to provide some basic functionality such as highlighting based on it: ->[!CAUTION] -> This is a full, incompatible, rewrite: Treat this as a different plugin you need to set up from scratch following the instructions below. If you can't or don't want to update, specify the [`master` branch](https://github.com/nvim-treesitter/nvim-treesitter/blob/master/README.md) (which is locked but will remain available for backward compatibility with Nvim 0.11). +![example-cpp](https://user-images.githubusercontent.com/2361214/202753610-e923bf4e-e88f-494b-bb1e-d22a7688446f.png) + +Traditional highlighting (left) vs Treesitter-based highlighting (right). +More examples can be found in [our gallery](https://github.com/nvim-treesitter/nvim-treesitter/wiki/Gallery). + +**Warning: Treesitter and nvim-treesitter highlighting are an experimental feature of Neovim. +Please consider the experience with this plug-in as experimental until Tree-Sitter support in Neovim is stable! +We recommend using the nightly builds of Neovim if possible. +You can find the current roadmap [here](https://github.com/nvim-treesitter/nvim-treesitter/projects/1). +The roadmap and all features of this plugin are open to change, and any suggestion will be highly appreciated!** + +Nvim-treesitter is based on three interlocking features: [**language parsers**](#language-parsers), [**queries**](#adding-queries), and [**modules**](#available-modules), where *modules* provide features – e.g., highlighting – based on *queries* for syntax objects extracted from a given buffer by *language parsers*. +Users will generally only need to interact with parsers and modules as explained in the next section. +For more detailed information on setting these up, see ["Advanced setup"](#advanced-setup). + +--- + +### Table of contents + +* [Quickstart](#quickstart) +* [Supported languages](#supported-languages) +* [Available modules](#available-modules) +* [Advanced setup](#advanced-setup) +* [Extra features](#extra-features) +* [Troubleshooting](#troubleshooting) + +--- # Quickstart ## Requirements -- Neovim 0.12.0 or later (nightly) -- `tar` and `curl` in your path -- [`tree-sitter-cli`](https://github.com/tree-sitter/tree-sitter/blob/master/crates/cli/README.md) (0.26.1 or later, installed via your package manager, **not npm**) -- a C compiler in your path (see ) - ->[!IMPORTANT] -> The current **support policy** for Neovim is -> * the _latest_ [stable release](https://github.com/neovim/neovim/releases/tag/stable), -> * the _latest_ [nightly prerelease](https://github.com/neovim/neovim/releases/tag/nightly). -> Other versions may work but are neither tested nor considered for fixes. +- **Neovim 0.8.0 or later** built with **tree-sitter 0.20.3+** (latest [nightly](https://github.com/neovim/neovim#install-from-source) recommended) +- `tar` and `curl` in your path (or alternatively `git`) +- A C compiler in your path and libstdc++ installed ([Windows users please read this!](https://github.com/nvim-treesitter/nvim-treesitter/wiki/Windows-support)). ## Installation You can install `nvim-treesitter` with your favorite package manager (or using the native `package` feature of vim, see `:h packages`). -This plugin is only guaranteed to work with specific versions of language parsers** (as specified in the `parser.lua` table). **When upgrading the plugin, you must make sure that all installed parsers are updated to the latest version** via `:TSUpdate`. -It is strongly recommended to automate this; e.g., using the following spec with [lazy.nvim](https://github.com/folke/lazy.nvim): +**NOTE: This plugin is only guaranteed to work with specific versions of language parsers** (as specified in the `lockfile.json`). **When upgrading the plugin, you must make sure that all installed parsers are updated to the latest version** via `:TSUpdate`. +It is strongly recommended to automate this; e.g., if you are using [vim-plug](https://github.com/junegunn/vim-plug), put this in your `init.vim` file: + +```vim +Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'} +``` + +For other plugin managers such as `packer.nvim`, see this [Installation page from the wiki](https://github.com/nvim-treesitter/nvim-treesitter/wiki/Installation) (Note that this page is community maintained). + +## Language parsers + +Treesitter uses a different _parser_ for every language, which needs to be generated via `tree-sitter-cli` from a `grammar.js` file, then compiled to a `.so` library that needs to be placed in neovim's `runtimepath` (typically under `parser/{language}.so`). +To simplify this, `nvim-treesitter` provides commands to automate this process. +If the language is already [supported by `nvim-treesitter`](#supported-languages), you can install it with +```vim +:TSInstall +``` +This command supports tab expansion. +You can also get a list of all available languages and their installation status with `:TSInstallInfo`. +Parsers not on this list can be added manually by following the steps described under ["Adding parsers"](#adding-parsers) below. + +To make sure a parser is at the latest compatible version (as specified in `nvim-treesitter`'s `lockfile.json`), use `:TSUpdate {language}`. To update all parsers unconditionally, use `:TSUpdate all` or just `:TSUpdate`. + +## Modules + +Each module provides a distinct tree-sitter-based feature such as [highlighting](#highlight), [indentation](#indentation), or [folding](#folding); see [`:h nvim-treesitter-modules`](doc/nvim-treesitter.txt) or ["Available modules"](#available-modules) below for a list of modules and their options. + +Following examples assume that you are configuring neovim with lua. If you are using vimscript, see `:help lua-heredoc`. +All modules are disabled by default and need to be activated explicitly in your `init.lua`, e.g., via ```lua -{ - 'nvim-treesitter/nvim-treesitter', - lazy = false, - build = ':TSUpdate' +require'nvim-treesitter.configs'.setup { + -- A list of parser names, or "all" + ensure_installed = { "c", "lua", "rust" }, + + -- Install parsers synchronously (only applied to `ensure_installed`) + sync_install = false, + + -- Automatically install missing parsers when entering buffer + -- Recommendation: set to false if you don't have `tree-sitter` CLI installed locally + auto_install = true, + + -- List of parsers to ignore installing (for "all") + ignore_install = { "javascript" }, + + ---- If you need to change the installation directory of the parsers (see -> Advanced Setup) + -- parser_install_dir = "/some/path/to/store/parsers", -- Remember to run vim.opt.runtimepath:append("/some/path/to/store/parsers")! + + highlight = { + -- `false` will disable the whole extension + enable = true, + + -- NOTE: these are the names of the parsers and not the filetype. (for example if you want to + -- disable highlighting for the `tex` filetype, you need to include `latex` in this list as this is + -- the name of the parser) + -- list of language that will be disabled + disable = { "c", "rust" }, + -- Or use a function for more flexibility, e.g. to disable slow treesitter highlight for large files + disable = function(lang, buf) + local max_filesize = 100 * 1024 -- 100 KB + local ok, stats = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(buf)) + if ok and stats and stats.size > max_filesize then + return true + end + end, + + -- Setting this to true will run `:h syntax` and tree-sitter at the same time. + -- Set this to `true` if you depend on 'syntax' being enabled (like for indentation). + -- Using this option may slow down your editor, and you may see some duplicate highlights. + -- Instead of true it can also be a list of languages + additional_vim_regex_highlighting = false, + }, } ``` ->[!IMPORTANT] -> This plugin does not support lazy-loading. +Each module can also be enabled or disabled interactively through the following commands: -## Setup - -`nvim-treesitter` can be configured by calling `setup`. **You do not need to call `setup` for `nvim-treesitter` to work using default values.** - -```lua -require('nvim-treesitter').setup { - -- Directory to install parsers and queries to (prepended to `runtimepath` to have priority) - install_dir = vim.fn.stdpath('data') .. '/site' -} -``` - -Parsers and queries can then be installed with - -```lua -require('nvim-treesitter').install { 'rust', 'javascript', 'zig' } -``` - -(This is a no-op if the parsers are already installed.) Note that this function runs asynchronously; for synchronous installation in a script context ("bootstrapping"), you need to `wait()` for it to finish: - -```lua -require('nvim-treesitter').install({ 'rust', 'javascript', 'zig' }):wait(300000) -- wait max. 5 minutes +```vim +:TSBufEnable {module} " enable module on current buffer +:TSBufDisable {module} " disable module on current buffer +:TSEnable {module} [{ft}] " enable module on every buffer. If filetype is specified, enable only for this filetype. +:TSDisable {module} [{ft}] " disable module on every buffer. If filetype is specified, disable only for this filetype. +:TSModuleInfo [{module}] " list information about modules state for each filetype ``` Check [`:h nvim-treesitter-commands`](doc/nvim-treesitter.txt) for a list of all available commands. +It may be necessary to reload the buffer (e.g., via `:e`) after enabling a module interactively. # Supported languages For `nvim-treesitter` to support a specific feature for a specific language requires both a parser for that language and an appropriate language-specific query file for that feature. -A list of the currently supported languages can be found [on this page](SUPPORTED_LANGUAGES.md). If you wish to add a new language or improve the queries for an existing one, please see our [contributing guide](CONTRIBUTING.md). +The following is a list of languages for which a parser can be installed through `:TSInstall`; a checked box means that `nvim-treesitter` also contains queries at least for the `highlight` module. -# Supported features +Experimental parsers are parsers that have a maintainer but are not stable enough for +daily use yet. -`nvim-treesitter` provides queries for the following features. **These are not automatically enabled.** +We are looking for maintainers to add more parsers and to write query files for their languages. Check our [tracking issue](https://github.com/nvim-treesitter/nvim-treesitter/issues/2282) for open language requests. -## Highlighting + + +- [x] [agda](https://github.com/AusCyberman/tree-sitter-agda) (maintained by @Decodetalkers) +- [x] [arduino](https://github.com/ObserverOfTime/tree-sitter-arduino) (maintained by @ObserverOfTime) +- [x] [astro](https://github.com/virchau13/tree-sitter-astro) (maintained by @virchau13) +- [ ] [awk](https://github.com/Beaglefoot/tree-sitter-awk) +- [x] [bash](https://github.com/tree-sitter/tree-sitter-bash) (maintained by @TravonteD) +- [x] [beancount](https://github.com/polarmutex/tree-sitter-beancount) (maintained by @polarmutex) +- [x] [bibtex](https://github.com/latex-lsp/tree-sitter-bibtex) (maintained by @theHamsta, @clason) +- [x] [blueprint](https://gitlab.com/gabmus/tree-sitter-blueprint.git) (experimental, maintained by @gabmus) +- [x] [c](https://github.com/tree-sitter/tree-sitter-c) (maintained by @vigoux) +- [x] [c_sharp](https://github.com/tree-sitter/tree-sitter-c-sharp) (maintained by @Luxed) +- [x] [clojure](https://github.com/sogaiu/tree-sitter-clojure) (maintained by @sogaiu) +- [x] [cmake](https://github.com/uyha/tree-sitter-cmake) (maintained by @uyha) +- [x] [comment](https://github.com/stsewd/tree-sitter-comment) (maintained by @stsewd) +- [x] [commonlisp](https://github.com/theHamsta/tree-sitter-commonlisp) (maintained by @theHamsta) +- [x] [cooklang](https://github.com/addcninblue/tree-sitter-cooklang) (maintained by @addcninblue) +- [x] [cpp](https://github.com/tree-sitter/tree-sitter-cpp) (maintained by @theHamsta) +- [x] [css](https://github.com/tree-sitter/tree-sitter-css) (maintained by @TravonteD) +- [x] [cuda](https://github.com/theHamsta/tree-sitter-cuda) (maintained by @theHamsta) +- [x] [d](https://github.com/CyberShadow/tree-sitter-d) (experimental, maintained by @nawordar) +- [x] [dart](https://github.com/UserNobody14/tree-sitter-dart) (maintained by @akinsho) +- [x] [devicetree](https://github.com/joelspadin/tree-sitter-devicetree) (maintained by @jedrzejboczar) +- [x] [diff](https://github.com/the-mikedavis/tree-sitter-diff) (maintained by @gbprod) +- [x] [dockerfile](https://github.com/camdencheek/tree-sitter-dockerfile) (maintained by @camdencheek) +- [x] [dot](https://github.com/rydesun/tree-sitter-dot) (maintained by @rydesun) +- [x] [ebnf](https://github.com/RubixDev/ebnf.git) (experimental, maintained by @RubixDev) +- [x] [eex](https://github.com/connorlay/tree-sitter-eex) (maintained by @connorlay) +- [x] [elixir](https://github.com/elixir-lang/tree-sitter-elixir) (maintained by @connorlay) +- [ ] [elm](https://github.com/elm-tooling/tree-sitter-elm) +- [x] [elvish](https://github.com/ckafi/tree-sitter-elvish) (maintained by @ckafi) +- [ ] [embedded_template](https://github.com/tree-sitter/tree-sitter-embedded-template) +- [x] [erlang](https://github.com/AbstractMachinesLab/tree-sitter-erlang) (maintained by @ostera) +- [x] [fennel](https://github.com/travonted/tree-sitter-fennel) (maintained by @TravonteD) +- [x] [fish](https://github.com/ram02z/tree-sitter-fish) (maintained by @ram02z) +- [x] [foam](https://github.com/FoamScience/tree-sitter-foam) (experimental, maintained by @FoamScience) +- [ ] [fortran](https://github.com/stadelmanma/tree-sitter-fortran) +- [x] [fusion](https://gitlab.com/jirgn/tree-sitter-fusion.git) (maintained by @jirgn) +- [x] [Godot (gdscript)](https://github.com/PrestonKnopp/tree-sitter-gdscript) (maintained by @Shatur) +- [x] [git_rebase](https://github.com/the-mikedavis/tree-sitter-git-rebase) (maintained by @gbprod) +- [x] [gitattributes](https://github.com/ObserverOfTime/tree-sitter-gitattributes) (maintained by @ObserverOfTime) +- [x] [gitcommit](https://github.com/gbprod/tree-sitter-gitcommit) (maintained by @gbprod) +- [x] [gitignore](https://github.com/shunsambongi/tree-sitter-gitignore) (maintained by @theHamsta) +- [x] [gleam](https://github.com/J3RN/tree-sitter-gleam) (maintained by @connorlay) +- [x] [Glimmer and Ember](https://github.com/alexlafroscia/tree-sitter-glimmer) (maintained by @NullVoxPopuli) +- [x] [glsl](https://github.com/theHamsta/tree-sitter-glsl) (maintained by @theHamsta) +- [x] [go](https://github.com/tree-sitter/tree-sitter-go) (maintained by @theHamsta, @WinWisely268) +- [x] [Godot Resources (gdresource)](https://github.com/PrestonKnopp/tree-sitter-godot-resource) (maintained by @pierpo) +- [x] [gomod](https://github.com/camdencheek/tree-sitter-go-mod) (maintained by @camdencheek) +- [x] [gowork](https://github.com/omertuc/tree-sitter-go-work) (maintained by @omertuc) +- [x] [graphql](https://github.com/bkegley/tree-sitter-graphql) (maintained by @bkegley) +- [ ] [hack](https://github.com/slackhq/tree-sitter-hack) +- [ ] [haskell](https://github.com/tree-sitter/tree-sitter-haskell) +- [x] [hcl](https://github.com/MichaHoffmann/tree-sitter-hcl) (maintained by @MichaHoffmann) +- [x] [heex](https://github.com/connorlay/tree-sitter-heex) (maintained by @connorlay) +- [x] [help](https://github.com/neovim/tree-sitter-vimdoc) (maintained by @vigoux) +- [x] [hjson](https://github.com/winston0410/tree-sitter-hjson) (maintained by @winston0410) +- [x] [hlsl](https://github.com/theHamsta/tree-sitter-hlsl) (maintained by @theHamsta) +- [x] [hocon](https://github.com/antosha417/tree-sitter-hocon) (maintained by @antosha417) +- [x] [html](https://github.com/tree-sitter/tree-sitter-html) (maintained by @TravonteD) +- [x] [http](https://github.com/rest-nvim/tree-sitter-http) (maintained by @NTBBloodbath) +- [x] [java](https://github.com/tree-sitter/tree-sitter-java) (maintained by @p00f) +- [x] [javascript](https://github.com/tree-sitter/tree-sitter-javascript) (maintained by @steelsojka) +- [x] [jq](https://github.com/flurie/tree-sitter-jq) (maintained by @ObserverOfTime) +- [x] [jsdoc](https://github.com/tree-sitter/tree-sitter-jsdoc) (maintained by @steelsojka) +- [x] [json](https://github.com/tree-sitter/tree-sitter-json) (maintained by @steelsojka) +- [x] [json5](https://github.com/Joakker/tree-sitter-json5) (maintained by @Joakker) +- [x] [JSON with comments](https://gitlab.com/WhyNotHugo/tree-sitter-jsonc.git) (maintained by @WhyNotHugo) +- [x] [jsonnet](https://github.com/sourcegraph/tree-sitter-jsonnet) (maintained by @nawordar) +- [x] [julia](https://github.com/tree-sitter/tree-sitter-julia) (maintained by @theHamsta) +- [x] [kotlin](https://github.com/fwcd/tree-sitter-kotlin) (maintained by @SalBakraa) +- [x] [lalrpop](https://github.com/traxys/tree-sitter-lalrpop) (maintained by @traxys) +- [x] [latex](https://github.com/latex-lsp/tree-sitter-latex) (maintained by @theHamsta, @clason) +- [x] [ledger](https://github.com/cbarrete/tree-sitter-ledger) (maintained by @cbarrete) +- [x] [llvm](https://github.com/benwilliamgraham/tree-sitter-llvm) (maintained by @benwilliamgraham) +- [x] [lua](https://github.com/MunifTanjim/tree-sitter-lua) (maintained by @muniftanjim) +- [x] [m68k](https://github.com/grahambates/tree-sitter-m68k) (maintained by @grahambates) +- [x] [make](https://github.com/alemuller/tree-sitter-make) (maintained by @lewis6991) +- [x] [markdown](https://github.com/MDeiml/tree-sitter-markdown) (experimental, maintained by @MDeiml) +- [x] [markdown_inline](https://github.com/MDeiml/tree-sitter-markdown) (experimental, maintained by @MDeiml) +- [x] [menhir](https://github.com/Kerl13/tree-sitter-menhir) (maintained by @Kerl13) +- [ ] [mermaid](https://github.com/monaqa/tree-sitter-mermaid) (experimental) +- [x] [meson](https://github.com/Decodetalkers/tree-sitter-meson) (maintained by @Decodetalkers) +- [ ] [nickel](https://github.com/nickel-lang/tree-sitter-nickel) +- [x] [ninja](https://github.com/alemuller/tree-sitter-ninja) (maintained by @alemuller) +- [x] [nix](https://github.com/cstrahan/tree-sitter-nix) (maintained by @leo60228) +- [x] [norg](https://github.com/nvim-neorg/tree-sitter-norg) (maintained by @JoeyGrajciar, @vhyrro) +- [x] [ocaml](https://github.com/tree-sitter/tree-sitter-ocaml) (maintained by @undu) +- [x] [ocaml_interface](https://github.com/tree-sitter/tree-sitter-ocaml) (maintained by @undu) +- [x] [ocamllex](https://github.com/atom-ocaml/tree-sitter-ocamllex) (maintained by @undu) +- [ ] [org](https://github.com/milisims/tree-sitter-org) +- [x] [pascal](https://github.com/Isopod/tree-sitter-pascal.git) (maintained by @Isopod) +- [x] [perl](https://github.com/ganezdragon/tree-sitter-perl) (maintained by @lcrownover) +- [x] [php](https://github.com/tree-sitter/tree-sitter-php) (maintained by @tk-shirasaka) +- [x] [phpdoc](https://github.com/claytonrcarter/tree-sitter-phpdoc) (experimental, maintained by @mikehaertl) +- [x] [pioasm](https://github.com/leo60228/tree-sitter-pioasm) (maintained by @leo60228) +- [x] [prisma](https://github.com/victorhqc/tree-sitter-prisma) (maintained by @elianiva) +- [x] [proto](https://github.com/mitchellh/tree-sitter-proto) (maintained by @fsouza) +- [x] [pug](https://github.com/zealot128/tree-sitter-pug) (experimental, maintained by @zealot128) +- [x] [python](https://github.com/tree-sitter/tree-sitter-python) (maintained by @stsewd, @theHamsta) +- [x] [ql](https://github.com/tree-sitter/tree-sitter-ql) (maintained by @pwntester) +- [x] [qmljs](https://github.com/yuja/tree-sitter-qmljs) (maintained by @Decodetalkers) +- [x] [Tree-sitter query language](https://github.com/nvim-treesitter/tree-sitter-query) (maintained by @steelsojka) +- [x] [r](https://github.com/r-lib/tree-sitter-r) (maintained by @echasnovski) +- [x] [racket](https://github.com/6cdh/tree-sitter-racket) (maintained by @6cdh) +- [x] [rasi](https://github.com/Fymyte/tree-sitter-rasi) (maintained by @Fymyte) +- [x] [regex](https://github.com/tree-sitter/tree-sitter-regex) (maintained by @theHamsta) +- [x] [rego](https://github.com/FallenAngel97/tree-sitter-rego) (maintained by @FallenAngel97) +- [x] [rnoweb](https://github.com/bamonroe/tree-sitter-rnoweb) (maintained by @bamonroe) +- [x] [rst](https://github.com/stsewd/tree-sitter-rst) (maintained by @stsewd) +- [x] [ruby](https://github.com/tree-sitter/tree-sitter-ruby) (maintained by @TravonteD) +- [x] [rust](https://github.com/tree-sitter/tree-sitter-rust) (maintained by @vigoux) +- [x] [scala](https://github.com/tree-sitter/tree-sitter-scala) (maintained by @stevanmilic) +- [x] [scheme](https://github.com/6cdh/tree-sitter-scheme) (maintained by @6cdh) +- [x] [scss](https://github.com/serenadeai/tree-sitter-scss) (maintained by @elianiva) +- [x] [slint](https://github.com/jrmoulton/tree-sitter-slint) (experimental, maintained by @jrmoulton) +- [x] [solidity](https://github.com/YongJieYongJie/tree-sitter-solidity) (maintained by @YongJieYongJie) +- [x] [sparql](https://github.com/BonaBeavis/tree-sitter-sparql) (maintained by @BonaBeavis) +- [x] [sql](https://github.com/derekstride/tree-sitter-sql) (maintained by @derekstride) +- [x] [supercollider](https://github.com/madskjeldgaard/tree-sitter-supercollider) (maintained by @madskjeldgaard) +- [x] [surface](https://github.com/connorlay/tree-sitter-surface) (maintained by @connorlay) +- [x] [svelte](https://github.com/Himujjal/tree-sitter-svelte) (maintained by @elianiva) +- [x] [swift](https://github.com/alex-pinkus/tree-sitter-swift) (maintained by @alex-pinkus) +- [x] [sxhkdrc](https://github.com/RaafatTurki/tree-sitter-sxhkdrc) (maintained by @RaafatTurki) +- [x] [teal](https://github.com/euclidianAce/tree-sitter-teal) (maintained by @euclidianAce) +- [x] [tiger](https://github.com/ambroisie/tree-sitter-tiger) (maintained by @ambroisie) +- [x] [tlaplus](https://github.com/tlaplus-community/tree-sitter-tlaplus) (maintained by @ahelwer, @susliko) +- [x] [todotxt](https://github.com/arnarg/tree-sitter-todotxt.git) (experimental, maintained by @arnarg) +- [x] [toml](https://github.com/ikatyang/tree-sitter-toml) (maintained by @tk-shirasaka) +- [x] [tsx](https://github.com/tree-sitter/tree-sitter-typescript) (maintained by @steelsojka) +- [x] [turtle](https://github.com/BonaBeavis/tree-sitter-turtle) (maintained by @BonaBeavis) +- [x] [twig](https://github.com/gbprod/tree-sitter-twig) (maintained by @gbprod) +- [x] [typescript](https://github.com/tree-sitter/tree-sitter-typescript) (maintained by @steelsojka) +- [x] [v](https://github.com/vlang/vls) (maintained by @kkharji) +- [x] [vala](https://github.com/vala-lang/tree-sitter-vala) (maintained by @Prince781) +- [x] [verilog](https://github.com/tree-sitter/tree-sitter-verilog) (maintained by @zegervdv) +- [x] [vhs](https://github.com/charmbracelet/tree-sitter-vhs) (maintained by @caarlos0) +- [x] [vim](https://github.com/vigoux/tree-sitter-viml) (maintained by @vigoux) +- [x] [vue](https://github.com/ikatyang/tree-sitter-vue) (maintained by @WhyNotHugo) +- [x] [wgsl](https://github.com/szebniok/tree-sitter-wgsl) (maintained by @szebniok) +- [x] [yaml](https://github.com/ikatyang/tree-sitter-yaml) (maintained by @stsewd) +- [x] [yang](https://github.com/Hubro/tree-sitter-yang) (maintained by @Hubro) +- [x] [zig](https://github.com/maxxnino/tree-sitter-zig) (maintained by @maxxnino) + -Treesitter highlighting is provided by Neovim, see `:h treesitter-highlight`. To enable it for a filetype, put `vim.treesitter.start()` in a `ftplugin/.lua` in your config directory, or place the following in your `init.lua`: +For related information on the supported languages, including related plugins, see [this wiki page](https://github.com/nvim-treesitter/nvim-treesitter/wiki/Supported-Languages-Information). + +# Available modules + +Modules provide the top-level features of `nvim-treesitter`. +The following is a list of modules included in `nvim-treesitter` and their configuration via `init.lua` (where multiple modules can be combined in a single call to `setup`). +Note that not all modules work for all languages (depending on the queries available for them). +Additional modules can be provided as [external plugins](https://github.com/nvim-treesitter/nvim-treesitter/wiki/Extra-modules-and-plugins). + +#### Highlight + +Consistent syntax highlighting. ```lua -vim.api.nvim_create_autocmd('FileType', { - pattern = { '' }, - callback = function() vim.treesitter.start() end, -}) +require'nvim-treesitter.configs'.setup { + highlight = { + enable = true, + -- Setting this to true will run `:h syntax` and tree-sitter at the same time. + -- Set this to `true` if you depend on 'syntax' being enabled (like for indentation). + -- Using this option may slow down your editor, and you may see some duplicate highlights. + -- Instead of true it can also be a list of languages + additional_vim_regex_highlighting = false, + }, +} ``` -## Folds - -Treesitter-based folding is provided by Neovim. To enable it, put the following in your `ftplugin` or `FileType` autocommand: +To customize the syntax highlighting of a capture, simply define or link a highlight group of the same name: ```lua -vim.wo[0][0].foldexpr = 'v:lua.vim.treesitter.foldexpr()' -vim.wo[0][0].foldmethod = 'expr' +-- Highlight the @foo.bar capture group with the "Identifier" highlight group +vim.api.nvim_set_hl(0, "@foo.bar", { link = "Identifier" }) ``` -## Indentation - -Treesitter-based indentation is provided by this plugin but considered **experimental**. To enable it, put the following in your `ftplugin` or `FileType` autocommand: +For a language-specific highlight, append the name of the language: ```lua -vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" +-- Highlight @foo.bar as "Identifier" only in Lua files +vim.api.nvim_set_hl(0, "@foo.bar.lua", { link = "Identifier" }) ``` -(Note the specific quotes used.) +See `:h treesitter-highlight-groups` for details. -## Injections +#### Incremental selection -Injections are used for multi-language documents, see `:h treesitter-language-injections`. No setup is needed. +Incremental selection based on the named nodes from the grammar. -## Locals +```lua +require'nvim-treesitter.configs'.setup { + incremental_selection = { + enable = true, + keymaps = { + init_selection = "gnn", + node_incremental = "grn", + scope_incremental = "grc", + node_decremental = "grm", + }, + }, +} +``` -These queries can be used to look up definitions and references to identifiers in a given scope. They are not used in this plugin and are provided for (limited) backward compatibility. +#### Indentation + +Indentation based on treesitter for the `=` operator. +**NOTE: This is an experimental feature**. + +```lua +require'nvim-treesitter.configs'.setup { + indent = { + enable = true + } +} +``` + +#### Folding + +Tree-sitter based folding. *(Technically not a module because it's per windows and not per buffer.)* + +```vim +set foldmethod=expr +set foldexpr=nvim_treesitter#foldexpr() +set nofoldenable " Disable folding at startup. +``` + +This will respect your `foldminlines` and `foldnestmax` settings. # Advanced setup -## Adding custom languages +## Changing the parser install directory + +If you want to install the parsers to a custom directory you can specify this +directory with `parser_install_dir` option in that is passed to `setup`. +`nvim-treesitter` will then install the parser files into this directory. + +This directory must be writeable and must be explicitly added to the +`runtimepath`. For example: + +``` lua + require'nvim-treesitter.configs'.setup { + parser_install_dir = "/some/path/to/store/parsers", + + ... + + } + vim.opt.runtimepath:append("/some/path/to/store/parsers") +``` + +If this option is not included in the setup options, or is explicitly set to +`nil` then the default install directories will be used. If this value is set +the default directories will be ignored. + +Bear in mind that any parser installed into a parser folder on the runtime path +will still be considered installed. (For example if +"~/.local/share/nvim/site/parser/c.so" exists then the "c" parser will be +considered installed, even though it is not in `parser_install_dir`) + +The default paths are: +1. first the package folder. Where `nvim-treesitter` is installed. +2. second the site directory. This is the "site" subdirectory of `stdpath("data")`. + +## Adding parsers If you have a parser that is not on the list of supported languages (either as a repository on Github or in a local directory), you can add it manually for use by `nvim-treesitter` as follows: -1. Add the following snippet in a `User TSUpdate` autocommand: +1. Clone the repository or [create a new project](https://tree-sitter.github.io/tree-sitter/creating-parsers#project-setup) in, say, `~/projects/tree-sitter-zimbu`. Make sure that the `tree-sitter-cli` executable is installed and in your path; see for installation instructions. +2. Run `tree-sitter generate` in this directory (followed by `tree-sitter test` for good measure). +3. Add the following snippet to your `init.lua`: ```lua -vim.api.nvim_create_autocmd('User', { pattern = 'TSUpdate', -callback = function() - require('nvim-treesitter.parsers').zimbu = { - install_info = { - url = 'https://github.com/zimbulang/tree-sitter-zimbu', - revision = , -- commit hash for revision to check out; HEAD if missing - -- optional entries: - branch = 'develop', -- only needed if different from default branch - location = 'parser', -- only needed if the parser is in subdirectory of a "monorepo" - generate = true, -- only needed if repo does not contain pre-generated `src/parser.c` - generate_from_json = false, -- only needed if repo does not contain `src/grammar.json` either - queries = 'queries/neovim', -- also install queries from given directory - }, - } -end}) +local parser_config = require "nvim-treesitter.parsers".get_parser_configs() +parser_config.zimbu = { + install_info = { + url = "~/projects/tree-sitter-zimbu", -- local path or git repo + files = {"src/parser.c"}, + -- optional entries: + branch = "main", -- default branch in case of git repo if different from master + generate_requires_npm = false, -- if stand-alone parser without npm dependencies + requires_generate_from_grammar = false, -- if folder contains pre-generated src/parser.c + }, + filetype = "zu", -- if filetype does not match the parser name +} ``` -Alternatively, if you have a local checkout, you can instead use +If you wish to set a specific parser for a filetype, you should extend the `filetype_to_parsername` table: ```lua - install_info = { - path = '~/parsers/tree-sitter-zimbu', - -- optional entries - location = 'parser', - generate = true, - generate_from_json = false, - queries = 'queries/neovim', -- symlink queries from given directory - }, -``` -This will always use the state of the directory as-is (i.e., `branch` and `revision` will be ignored). - -2. If the parser name differs from the filetype(s) used by Neovim, you need to register the parser via - -```lua -vim.treesitter.language.register('zimbu', { 'zu' }) +local ft_to_parser = require"nvim-treesitter.parsers".filetype_to_parsername +ft_to_parser.someft = "python" -- the someft filetype will use the python parser and queries. ``` -If Neovim does not detect your language's filetype by default, you can use [Neovim's `vim.filetype.add()`]() to add a custom detection rule. +4. Start `nvim` and `:TSInstall zimbu`. -3. Start `nvim` and `:TSInstall zimbu`. +You can also skip step 2 and use `:TSInstallFromGrammar zimbu` to install directly from a `grammar.js` in the top-level directory specified by `url`. +Once the parser is installed, you can update it (from the latest revision of the `main` branch if `url` is a Github repository) with `:TSUpdate zimbu`. ->[!IMPORTANT] -> If the parser requires an external scanner, this must be written in C. +Note that neither `:TSInstall` nor `:TSInstallFromGrammar` copy query files from the grammar repository. +If you want your installed grammar to be useful, you must manually [add query files](#adding-queries) to your local nvim-treesitter installation. +Note also that module functionality is only triggered if your language's filetype is correctly identified. +If Neovim does not detect your language's filetype by default, you can use [Neovim's `vim.filetype.add()`](https://neovim.io/doc/user/lua.html#vim.filetype.add()) to add a custom detection rule. -### Modifying parsers - -You can use the same approach for overriding parser information. E.g., if you always want to generate the `lua` parser from grammar, add - -```lua -vim.api.nvim_create_autocmd('User', { pattern = 'TSUpdate', -callback = function() - require('nvim-treesitter.parsers').lua.install_info.generate = true -end}) -``` +If you use a git repository for your parser and want to use a specific version, you can set the `revision` key +in the `install_info` table for you parser config. ## Adding queries -Queries can be placed anywhere in your `runtimepath` under `queries/`, with earlier directories taking precedence unless the queries are marked with `; extends`; see [`:h treesitter-query-modelines`](https://neovim.io/doc/user/treesitter.html#treesitter-query-modeline). +Queries are what `nvim-treesitter` uses to extract information from the syntax tree; +they are located in the `queries/{language}/*` runtime directories (see `:h rtp`), +like the `queries` folder of this plugin, e.g. `queries/{language}/{locals,highlights,textobjects}.scm`. +Other modules may require additional queries such as `folding.scm`. You can find a +list of all supported capture names in [CONTRIBUTING.md](https://github.com/nvim-treesitter/nvim-treesitter/blob/master/CONTRIBUTING.md#parser-configurations). + +All queries found in the runtime directories will be combined. +By convention, if you want to write a query, use the `queries/` directory, +but if you want to extend a query use the `after/queries/` directory. + +If you want to completely override a query, you can use `:h set_query()`. +For example, to override the `injections` queries from `c` with your own: + +```lua +require("vim.treesitter.query").set_query("c", "injections", "(comment) @comment") +``` + +Note: when using `set_query`, all queries in the runtime directories will be ignored. + +## Adding modules + +If you wish you write your own module, you need to support + +- tree-sitter language detection support; +- attaching and detaching to buffers; +- all nvim-treesitter commands. + +At the top level, you can use the `define_modules` function to define one or more modules or module groups: + +```lua +require'nvim-treesitter'.define_modules { + my_cool_plugin = { + attach = function(bufnr, lang) + -- Do cool stuff here + end, + detach = function(bufnr) + -- Undo cool stuff here + end, + is_supported = function(lang) + -- Check if the language is supported + end + } +} +``` + +with the following properties: + +- `module_path` specifies a require path (string) that exports a module with an `attach` and `detach` function. This is not required if the functions are on this definition. +- `enable` determines if the module is enabled by default. This is usually overridden by the user. +- `disable` takes a list of languages that this module is disabled for. This is usually overridden by the user. +- `is_supported` takes a function that takes a language and determines if this module supports that language. +- `attach` takes a function that attaches to a buffer. This is required if `module_path` is not provided. +- `detach` takes a function that detaches from a buffer. This is required if `module_path` is not provided. + +# Extra features + +### Statusline indicator + +```vim +echo nvim_treesitter#statusline(90) " 90 can be any length +module->expression_statement->call->identifier +``` + +### Utilities + +You can get some utility functions with + +```lua +local ts_utils = require 'nvim-treesitter.ts_utils' +``` + +Check [`:h nvim-treesitter-utils`](doc/nvim-treesitter.txt) for more information. + +# Troubleshooting + +Before doing anything, make sure you have the latest version of this plugin and run `:checkhealth nvim-treesitter`. +It can also help to update the parsers via `:TSUpdate`. + +#### Feature `X` does not work for `{language}`... + +First, check the `health#nvim_treesitter#check` and the `health#treesitter#check` sections of `:checkhealth` for any warning. +If there is one, it's highly likely that this is the cause of the problem. + +Next check the `## Parser/Features` subsection of the `health#nvim_treesitter#check` section of `:checkhealth` to ensure the desired module is enabled for your language. +If not, you might be missing query files; see [Adding queries](#adding-queries). + +Finally, ensure Neovim is correctly identifying your language's filetype using the `:echo &filetype` command while one of your language's files is open in Neovim. +If not, add a short Vimscript file to nvim-treesitter's `ftdetect` runtime directory following [Neovim's documentation](https://neovim.io/doc/user/filetype.html#new-filetype) on filetype detection. +You can also quickly & temporarily set the filetype for a single buffer with the `:set filetype=langname` command to test whether it fixes the problem. + +If everything is okay, then it might be an actual error. +In that case, feel free to [open an issue here](https://github.com/nvim-treesitter/nvim-treesitter/issues/new/choose). + +#### I get `module 'vim.treesitter.query' not found` + +Make sure you have the latest version of Neovim. + +#### I get `Error detected while processing .../plugin/nvim-treesitter.vim` every time I open Neovim + +This is probably due to a change in a parser's grammar or its queries. +Try updating the parser that you suspect has changed (`:TSUpdate {language}`) or all of them (`:TSUpdate`). +If the error persists after updating all parsers, +please [open an issue](https://github.com/nvim-treesitter/nvim-treesitter/issues/new/choose). + +#### I get `query error: invalid node type at position` + +This could be due a query file outside this plugin using outdated nodes, +or due to an outdated parser. + +- Make sure you have the parsers up to date with `:TSUpdate` +- Make sure you don't have more than one `parser` runtime directory. + You can execute this command `:echo nvim_get_runtime_file('parser', v:true)` to find all runtime directories. + If you get more than one path, remove the ones that are outside this plugin (`nvim-treesitter` directory), + so the correct version of the parser is used. + +#### I experience weird highlighting issues similar to [#78](https://github.com/nvim-treesitter/nvim-treesitter/issues/78) + +This is a well known issue, which arises when the tree and the buffer have gotten out of sync. +As this is an upstream issue, we don't have any definite fix. +To get around this, you can force reparsing the buffer with + +```vim +:write | edit | TSBufEnable highlight +``` + +This will save, restore and enable highlighting for the current buffer. + +#### I experience bugs when using `nvim-treesitter`'s `foldexpr` similar to [#194](https://github.com/nvim-treesitter/nvim-treesitter/issues/194) + +This might happen, and is known to happen, with `vim-clap`. +To avoid these kind of errors, please use `setlocal` instead of `set` for the respective filetypes. + +#### I run into errors like `module 'nvim-treesitter.configs' not found` at startup + +This is because of `rtp` management in `nvim`, adding `packadd +nvim-treesitter` should fix the issue. + +#### I want to use Git instead of curl for downloading the parsers + +In your Lua config: + +```lua +require("nvim-treesitter.install").prefer_git = true +``` + +#### I want to use a HTTP proxy for downloading the parsers + +You can either configure curl to use additional CLI arguments in your Lua config: +```lua +require("nvim-treesitter.install").command_extra_args = { + curl = { "--proxy", "" }, +} +``` +or you can configure git via `.gitconfig` and use git instead of curl + +```lua +require("nvim-treesitter.install").prefer_git = true +``` + +#### I want to use a mirror instead of "https://github.com/" + +In your Lua config: + +```lua +for _, config in pairs(require("nvim-treesitter.parsers").get_parser_configs()) do + config.install_info.url = config.install_info.url:gsub("https://github.com/", "something else") +end + +require'nvim-treesitter.configs'.setup { + -- + -- +} +``` diff --git a/SUPPORTED_LANGUAGES.md b/SUPPORTED_LANGUAGES.md deleted file mode 100644 index 98b798ab9..000000000 --- a/SUPPORTED_LANGUAGES.md +++ /dev/null @@ -1,365 +0,0 @@ -# Supported languages - -The following is a list of languages for which a parser can be installed through `:TSInstall`. - -Legend: -- **Tier:** _stable_ (updates follow semver releases), _unstable_ (updates follow HEAD), _unmaintained_ (no automatic updates), or _unsupported_ (known to be broken, cannot be installed) -- **Queries** available for **H**ighlights, **F**olds, **I**ndents, In**J**ections, **L**ocals -- **Maintainer** of queries in nvim-treesitter (may be different from parser maintainer!) - - - -Language | Tier | Queries | Maintainer --------- |:----:|:-------:| ---------- -[ada](https://github.com/briot/tree-sitter-ada) | unstable | `HF JL` | @briot -[agda](https://github.com/tree-sitter/tree-sitter-agda) | unstable | `HF J ` | @Decodetalkers -[angular](https://github.com/dlvandenberg/tree-sitter-angular) | unstable | `HFIJL` | @dlvandenberg -[apex](https://github.com/aheber/tree-sitter-sfapex) | unstable | `HF JL` | @aheber, @xixiafinland -[arduino](https://github.com/tree-sitter-grammars/tree-sitter-arduino) | unstable | `HFIJL` | @ObserverOfTime -[asm](https://github.com/RubixDev/tree-sitter-asm) | unstable | `H  J ` | @RubixDev -[astro](https://github.com/virchau13/tree-sitter-astro) | unstable | `HFIJL` | @virchau13 -[authzed](https://github.com/mleonidas/tree-sitter-authzed) | unstable | `H  J ` | @mattpolzin -[awk](https://github.com/Beaglefoot/tree-sitter-awk) | unstable | `H  J ` | -[bash](https://github.com/tree-sitter/tree-sitter-bash) | unstable | `HFIJL` | @TravonteD -[bass](https://github.com/vito/tree-sitter-bass) | unstable | `HFIJL` | @amaanq -[beancount](https://github.com/polarmutex/tree-sitter-beancount) | unstable | `HF J ` | @polarmutex -[bibtex](https://github.com/latex-lsp/tree-sitter-bibtex) | unstable | `HFIJ ` | @theHamsta, @clason -[bicep](https://github.com/tree-sitter-grammars/tree-sitter-bicep) | unstable | `HFIJL` | @amaanq -[bitbake](https://github.com/tree-sitter-grammars/tree-sitter-bitbake) | unstable | `HFIJL` | @amaanq -[blade](https://github.com/EmranMR/tree-sitter-blade) | unstable | `HFIJ ` | @calebdw -[bp](https://github.com/ambroisie/tree-sitter-bp)[^bp] | unstable | `HFIJL` | @ambroisie -[bpftrace](https://github.com/sgruszka/tree-sitter-bpftrace) | unstable | `H  J ` | @sgruszka -[brightscript](https://github.com/ajdelcimmuto/tree-sitter-brightscript) | unstable | `HFIJ ` | @ajdelcimmuto -[c](https://github.com/tree-sitter/tree-sitter-c) | unstable | `HFIJL` | @amaanq -[c3](https://github.com/c3lang/tree-sitter-c3) | unstable | `HFIJ ` | @cbuttner -[c_sharp](https://github.com/tree-sitter/tree-sitter-c-sharp) | unstable | `HF JL` | @amaanq -[caddy](https://github.com/opa-oz/tree-sitter-caddy) | unmaintained | `HFIJ ` | -[cairo](https://github.com/tree-sitter-grammars/tree-sitter-cairo) | unstable | `HFIJL` | @amaanq -[capnp](https://github.com/tree-sitter-grammars/tree-sitter-capnp) | unstable | `HFIJL` | @amaanq -[chatito](https://github.com/tree-sitter-grammars/tree-sitter-chatito) | unstable | `HFIJL` | @ObserverOfTime -[circom](https://github.com/Decurity/tree-sitter-circom) | unstable | `HF JL` | @alexandr-martirosyan -[clojure](https://github.com/sogaiu/tree-sitter-clojure) | unstable | `HF JL` | @NoahTheDuke -[cmake](https://github.com/uyha/tree-sitter-cmake) | unstable | `HFIJ ` | @uyha -[comment](https://github.com/stsewd/tree-sitter-comment) | unstable | `H    ` | @stsewd -[commonlisp](https://github.com/tree-sitter-grammars/tree-sitter-commonlisp) | unstable | `HF JL` | @theHamsta -[cooklang](https://github.com/addcninblue/tree-sitter-cooklang) | unstable | `H  J ` | @addcninblue -[corn](https://github.com/jakestanger/tree-sitter-corn) | unstable | `HFIJL` | @jakestanger -[cpon](https://github.com/tree-sitter-grammars/tree-sitter-cpon) | unstable | `HFIJL` | @amaanq -[cpp](https://github.com/tree-sitter/tree-sitter-cpp) | unstable | `HFIJL` | @theHamsta -[css](https://github.com/tree-sitter/tree-sitter-css) | unstable | `HFIJ ` | @TravonteD -[csv](https://github.com/tree-sitter-grammars/tree-sitter-csv) | unstable | `H    ` | @amaanq -[cuda](https://github.com/tree-sitter-grammars/tree-sitter-cuda) | unstable | `HFIJL` | @theHamsta -[cue](https://github.com/eonpatapon/tree-sitter-cue) | unstable | `HFIJL` | @amaanq -[cylc](https://github.com/elliotfontaine/tree-sitter-cylc) | unstable | `HFIJ ` | @elliotfontaine -[d](https://github.com/gdamore/tree-sitter-d) | unstable | `HFIJL` | @amaanq -[dart](https://github.com/UserNobody14/tree-sitter-dart) | unstable | `HFIJL` | @akinsho -[desktop](https://github.com/ValdezFOmar/tree-sitter-desktop) | stable | `HF J ` | @ValdezFOmar -[devicetree](https://github.com/joelspadin/tree-sitter-devicetree) | unstable | `HFIJL` | @jedrzejboczar -[dhall](https://github.com/jbellerb/tree-sitter-dhall) | unstable | `HF J ` | @amaanq -[diff](https://github.com/tree-sitter-grammars/tree-sitter-diff) | unstable | `HF J ` | @gbprod -[disassembly](https://github.com/ColinKennedy/tree-sitter-disassembly) | unstable | `H  J ` | @ColinKennedy -[djot](https://github.com/treeman/tree-sitter-djot) | unstable | `HFIJL` | @NoahTheDuke -[dockerfile](https://github.com/camdencheek/tree-sitter-dockerfile) | unstable | `H  J ` | @camdencheek -[dot](https://github.com/rydesun/tree-sitter-dot) | unstable | `HFIJ ` | @rydesun -[doxygen](https://github.com/tree-sitter-grammars/tree-sitter-doxygen) | unstable | `H IJ ` | @amaanq -[dtd](https://github.com/tree-sitter-grammars/tree-sitter-xml) | unstable | `HF JL` | @ObserverOfTime -[earthfile](https://github.com/glehmann/tree-sitter-earthfile) | unstable | `H  J ` | @glehmann -[ebnf](https://github.com/RubixDev/ebnf) | unstable | `H  J ` | @RubixDev -ecma (queries only)[^ecma] | unstable | `HFIJL` | @steelsojka -[editorconfig](https://github.com/ValdezFOmar/tree-sitter-editorconfig) | stable | `HF J ` | @ValdezFOmar -[eds](https://github.com/uyha/tree-sitter-eds) | unstable | `HF   ` | @uyha -[eex](https://github.com/connorlay/tree-sitter-eex) | unstable | `H  J ` | @connorlay -[elixir](https://github.com/elixir-lang/tree-sitter-elixir) | unstable | `HFIJL` | @connorlay -[elm](https://github.com/elm-tooling/tree-sitter-elm) | unstable | `HF J ` | @zweimach -[elsa](https://github.com/glapa-grossklag/tree-sitter-elsa) | unstable | `HFIJL` | @glapa-grossklag, @amaanq -[elvish](https://github.com/elves/tree-sitter-elvish) | unstable | `H  J ` | @elves -[embedded_template](https://github.com/tree-sitter/tree-sitter-embedded-template) | unstable | `H  J ` | -[enforce](https://github.com/simonvic/tree-sitter-enforce) | unstable | `HFIJL` | @simonvic -[erlang](https://github.com/WhatsApp/tree-sitter-erlang) | unstable | `HF J ` | @filmor -[facility](https://github.com/FacilityApi/tree-sitter-facility) | unstable | `HFIJ ` | @bryankenote -[faust](https://github.com/khiner/tree-sitter-faust) | unstable | `H  J ` | @khiner -[fennel](https://github.com/alexmozaidze/tree-sitter-fennel) | unstable | `HF JL` | @alexmozaidze -[fidl](https://github.com/google/tree-sitter-fidl) | unstable | `HF J ` | @chaopeng -[firrtl](https://github.com/tree-sitter-grammars/tree-sitter-firrtl) | unstable | `HFIJL` | @amaanq -[fish](https://github.com/ram02z/tree-sitter-fish) | unstable | `HFIJL` | @ram02z -[foam](https://github.com/FoamScience/tree-sitter-foam) | unstable | `HFIJL` | @FoamScience -[forth](https://github.com/AlexanderBrevig/tree-sitter-forth) | unstable | `HFIJL` | @amaanq -[fortran](https://github.com/stadelmanma/tree-sitter-fortran) | unstable | `HFIJ ` | @amaanq -[fsh](https://github.com/mgramigna/tree-sitter-fsh) | unstable | `H  J ` | @mgramigna -[fsharp](https://github.com/ionide/tree-sitter-fsharp) | unstable | `H  J ` | @nsidorenco -[func](https://github.com/tree-sitter-grammars/tree-sitter-func) | unstable | `H  J ` | @amaanq -[gap](https://github.com/gap-system/tree-sitter-gap)[^gap] | unstable | `HF JL` | @reiniscirpons -[gaptst](https://github.com/gap-system/tree-sitter-gaptst)[^gaptst] | unstable | `HF J ` | @reiniscirpons -[gdscript](https://github.com/PrestonKnopp/tree-sitter-gdscript)[^gdscript] | unmaintained | `HFIJL` | -[gdshader](https://github.com/airblast-dev/tree-sitter-gdshader) | unstable | `H  J ` | @airblast-dev -[git_config](https://github.com/the-mikedavis/tree-sitter-git-config) | unstable | `HF J ` | @amaanq -[git_rebase](https://github.com/the-mikedavis/tree-sitter-git-rebase) | unstable | `H  J ` | @gbprod -[gitattributes](https://github.com/tree-sitter-grammars/tree-sitter-gitattributes) | unstable | `H  JL` | @ObserverOfTime -[gitcommit](https://github.com/gbprod/tree-sitter-gitcommit) | unstable | `H  J ` | @gbprod -[gitignore](https://github.com/shunsambongi/tree-sitter-gitignore) | unstable | `H  J ` | @theHamsta -[gleam](https://github.com/gleam-lang/tree-sitter-gleam) | unstable | `HFIJL` | @amaanq -[glimmer](https://github.com/ember-tooling/tree-sitter-glimmer)[^glimmer] | unstable | `HFIJL` | @NullVoxPopuli -[glimmer_javascript](https://github.com/NullVoxPopuli/tree-sitter-glimmer-javascript) | unstable | `HFIJL` | @NullVoxPopuli -[glimmer_typescript](https://github.com/NullVoxPopuli/tree-sitter-glimmer-typescript) | unstable | `HFIJ ` | @NullVoxPopuli -[glsl](https://github.com/tree-sitter-grammars/tree-sitter-glsl) | unstable | `HFIJL` | @theHamsta -[gn](https://github.com/tree-sitter-grammars/tree-sitter-gn) | unstable | `HFIJL` | @amaanq -[gnuplot](https://github.com/dpezto/tree-sitter-gnuplot) | unstable | `H  J ` | @dpezto -[go](https://github.com/tree-sitter/tree-sitter-go) | unstable | `HFIJL` | @theHamsta, @WinWisely268 -[goctl](https://github.com/chaozwn/tree-sitter-goctl) | unstable | `HFIJ ` | @chaozwn -[godot_resource](https://github.com/PrestonKnopp/tree-sitter-godot-resource)[^godot_resource] | unstable | `HF JL` | @pierpo -[gomod](https://github.com/camdencheek/tree-sitter-go-mod) | unstable | `H  J ` | @camdencheek -[gosum](https://github.com/tree-sitter-grammars/tree-sitter-go-sum) | unstable | `H    ` | @amaanq -[gotmpl](https://github.com/ngalaiko/tree-sitter-go-template) | unstable | `HF JL` | @qvalentin -[gowork](https://github.com/omertuc/tree-sitter-go-work) | unstable | `H  J ` | @omertuc -[gpg](https://github.com/tree-sitter-grammars/tree-sitter-gpg-config) | unstable | `H  J ` | @ObserverOfTime -[graphql](https://github.com/bkegley/tree-sitter-graphql) | unstable | `H IJ ` | @bkegley -[gren](https://github.com/MaeBrooks/tree-sitter-gren) | unstable | `H  J ` | @MaeBrooks -[groovy](https://github.com/murtaza64/tree-sitter-groovy) | unstable | `HFIJL` | @murtaza64 -[groq](https://github.com/ajrussellaudio/tree-sitter-groq) | unstable | `HFIJ ` | @ajrussellaudio -[gstlaunch](https://github.com/tree-sitter-grammars/tree-sitter-gstlaunch) | unstable | `H    ` | @theHamsta -[hack](https://github.com/slackhq/tree-sitter-hack) | unstable | `H  J ` | -[hare](https://github.com/tree-sitter-grammars/tree-sitter-hare) | unstable | `HFIJL` | @amaanq -[haskell](https://github.com/tree-sitter-grammars/tree-sitter-haskell) | unstable | `HF JL` | @mrcjkb -[haskell_persistent](https://github.com/MercuryTechnologies/tree-sitter-haskell-persistent) | unstable | `HF   ` | @lykahb -[hcl](https://github.com/tree-sitter-grammars/tree-sitter-hcl) | unstable | `HFIJ ` | @MichaHoffmann -[heex](https://github.com/connorlay/tree-sitter-heex) | unstable | `HFIJL` | @connorlay -[helm](https://github.com/ngalaiko/tree-sitter-go-template) | unstable | `HF JL` | @qvalentin -[hjson](https://github.com/winston0410/tree-sitter-hjson) | unstable | `HFIJL` | @winston0410 -[hlsl](https://github.com/tree-sitter-grammars/tree-sitter-hlsl) | unstable | `HFIJL` | @theHamsta -[hlsplaylist](https://github.com/Freed-Wu/tree-sitter-hlsplaylist) | unstable | `H  J ` | @Freed-Wu -[hocon](https://github.com/antosha417/tree-sitter-hocon) | unstable | `HF J ` | @antosha417 -[hoon](https://github.com/urbit-pilled/tree-sitter-hoon) | unstable | `HF JL` | @urbit-pilled -[html](https://github.com/tree-sitter/tree-sitter-html) | unstable | `HFIJL` | @TravonteD -html_tags (queries only)[^html_tags] | unstable | `H IJ ` | @TravonteD -[htmldjango](https://github.com/interdependence/tree-sitter-htmldjango) | unstable | `HFIJ ` | @ObserverOfTime -[http](https://github.com/rest-nvim/tree-sitter-http) | unstable | `HF J ` | @amaanq, @NTBBloodbath -[hurl](https://github.com/pfeiferj/tree-sitter-hurl) | unstable | `HFIJ ` | @pfeiferj -[hyprlang](https://github.com/tree-sitter-grammars/tree-sitter-hyprlang) | unstable | `HFIJ ` | @luckasRanarison -[idl](https://github.com/cathaysia/tree-sitter-idl) | unstable | `H IJ ` | @cathaysia -[idris](https://github.com/kayhide/tree-sitter-idris) | unstable | `HF JL` | -[ini](https://github.com/justinmk/tree-sitter-ini) | unstable | `HF J ` | @theHamsta -[inko](https://github.com/inko-lang/tree-sitter-inko) | stable | `HFIJL` | @yorickpeterse -[ispc](https://github.com/tree-sitter-grammars/tree-sitter-ispc) | unstable | `HFIJL` | @fab4100 -[janet_simple](https://github.com/sogaiu/tree-sitter-janet-simple) | unstable | `HF JL` | @sogaiu -[java](https://github.com/tree-sitter/tree-sitter-java) | unstable | `HFIJL` | @p00f -[javadoc](https://github.com/rmuir/tree-sitter-javadoc) | unstable | `H IJ ` | @rmuir -[javascript](https://github.com/tree-sitter/tree-sitter-javascript) | unstable | `HFIJL` | @steelsojka -[jinja](https://github.com/cathaysia/tree-sitter-jinja)[^jinja] | unstable | `H  J ` | @cathaysia -[jinja_inline](https://github.com/cathaysia/tree-sitter-jinja)[^jinja_inline] | unstable | `H  J ` | @cathaysia -[jjdescription](https://github.com/ribru17/tree-sitter-jjdescription) | stable | `H  J ` | @ribru17 -[jq](https://github.com/flurie/tree-sitter-jq) | unstable | `H  JL` | @ObserverOfTime -[jsdoc](https://github.com/tree-sitter/tree-sitter-jsdoc) | unstable | `H    ` | @steelsojka -[json](https://github.com/tree-sitter/tree-sitter-json) | unstable | `HFIJL` | @steelsojka -[json5](https://github.com/Joakker/tree-sitter-json5) | unstable | `H  J ` | @Joakker -[jsonnet](https://github.com/sourcegraph/tree-sitter-jsonnet) | unstable | `HF JL` | @nawordar -jsx (queries only)[^jsx] | unstable | `HFIJ ` | @steelsojka -[julia](https://github.com/tree-sitter-grammars/tree-sitter-julia) | unstable | `HFIJL` | @clason -[just](https://github.com/IndianBoy42/tree-sitter-just) | unstable | `HFIJL` | @Hubro -[kcl](https://github.com/kcl-lang/tree-sitter-kcl) | unstable | `HF J ` | @bertbaron -[kconfig](https://github.com/tree-sitter-grammars/tree-sitter-kconfig) | unstable | `HFIJL` | @amaanq -[kdl](https://github.com/tree-sitter-grammars/tree-sitter-kdl) | unstable | `HFIJL` | @amaanq -[kitty](https://github.com/OXY2DEV/tree-sitter-kitty) | unstable | `H  J ` | @OXY2DEV -[kos](https://github.com/kos-lang/tree-sitter-kos) | unstable | `HF JL` | @cdragan -[kotlin](https://github.com/fwcd/tree-sitter-kotlin) | unstable | `HF JL` | -[koto](https://github.com/koto-lang/tree-sitter-koto) | unstable | `HF JL` | @irh -[kusto](https://github.com/Willem-J-an/tree-sitter-kusto) | unstable | `H  J ` | @Willem-J-an -[lalrpop](https://github.com/traxys/tree-sitter-lalrpop) | unstable | `HF JL` | @traxys -[latex](https://github.com/latex-lsp/tree-sitter-latex) | unstable | `HF J ` | @theHamsta, @clason -[ledger](https://github.com/cbarrete/tree-sitter-ledger) | unstable | `HFIJ ` | @cbarrete -[leo](https://github.com/r001/tree-sitter-leo) | unstable | `H IJ ` | @r001 -[linkerscript](https://github.com/tree-sitter-grammars/tree-sitter-linkerscript) | unstable | `HFIJL` | @amaanq -[liquid](https://github.com/hankthetank27/tree-sitter-liquid) | unstable | `H  J ` | @hankthetank27 -[liquidsoap](https://github.com/savonet/tree-sitter-liquidsoap) | unstable | `HFIJL` | @toots -[llvm](https://github.com/benwilliamgraham/tree-sitter-llvm) | unstable | `H  J ` | @benwilliamgraham -[lua](https://github.com/tree-sitter-grammars/tree-sitter-lua) | unstable | `HFIJL` | @muniftanjim -[luadoc](https://github.com/tree-sitter-grammars/tree-sitter-luadoc) | unstable | `H    ` | @amaanq -[luap](https://github.com/tree-sitter-grammars/tree-sitter-luap)[^luap] | unstable | `H    ` | @amaanq -[luau](https://github.com/tree-sitter-grammars/tree-sitter-luau) | unstable | `HFIJL` | @amaanq -[m68k](https://github.com/grahambates/tree-sitter-m68k) | unstable | `HF JL` | @grahambates -[make](https://github.com/tree-sitter-grammars/tree-sitter-make) | unstable | `HF J ` | @lewis6991 -[markdown](https://github.com/tree-sitter-grammars/tree-sitter-markdown)[^markdown] | unstable | `HFIJ ` | @MDeiml -[markdown_inline](https://github.com/tree-sitter-grammars/tree-sitter-markdown)[^markdown_inline] | unstable | `H  J ` | @MDeiml -[matlab](https://github.com/acristoffers/tree-sitter-matlab) | unstable | `HFIJL` | @acristoffers -[menhir](https://github.com/Kerl13/tree-sitter-menhir) | unstable | `H  J ` | @Kerl13 -[mermaid](https://github.com/monaqa/tree-sitter-mermaid) | unstable | `HFIJ ` | -[meson](https://github.com/tree-sitter-grammars/tree-sitter-meson) | unstable | `HFIJ ` | @Decodetalkers -[mlir](https://github.com/artagnon/tree-sitter-mlir) | unstable | `H  JL` | @artagnon -[muttrc](https://github.com/neomutt/tree-sitter-muttrc) | unstable | `H  J ` | @Freed-Wu -[nasm](https://github.com/naclsn/tree-sitter-nasm) | unstable | `H  J ` | @ObserverOfTime -[nginx](https://github.com/opa-oz/tree-sitter-nginx) | unstable | `HF J ` | @opa-oz -[nickel](https://github.com/nickel-lang/tree-sitter-nickel) | unstable | `H IJ ` | -[nim](https://github.com/alaviss/tree-sitter-nim) | unstable | `HF JL` | @aMOPel -[nim_format_string](https://github.com/aMOPel/tree-sitter-nim-format-string) | unstable | `H  J ` | @aMOPel -[ninja](https://github.com/alemuller/tree-sitter-ninja) | unstable | `HFIJ ` | @alemuller -[nix](https://github.com/nix-community/tree-sitter-nix) | unstable | `HFIJL` | @leo60228, @mrcjkb, @zimbatm -[nqc](https://github.com/tree-sitter-grammars/tree-sitter-nqc) | unstable | `HFIJL` | @amaanq -[nu](https://github.com/nushell/tree-sitter-nu) | unstable | `HFIJ ` | @abhisheksingh0x558 -[objc](https://github.com/tree-sitter-grammars/tree-sitter-objc) | unstable | `HFIJL` | @amaanq -[objdump](https://github.com/ColinKennedy/tree-sitter-objdump) | unstable | `H  J ` | @ColinKennedy -[ocaml](https://github.com/tree-sitter/tree-sitter-ocaml) | unstable | `HFIJL` | @undu -[ocaml_interface](https://github.com/tree-sitter/tree-sitter-ocaml) | unstable | `HFIJL` | @undu -[ocamllex](https://github.com/atom-ocaml/tree-sitter-ocamllex) | unstable | `H  J ` | @undu -[odin](https://github.com/tree-sitter-grammars/tree-sitter-odin) | unstable | `HFIJL` | @amaanq -[pascal](https://github.com/Isopod/tree-sitter-pascal) | unstable | `HFIJL` | @Isopod -[passwd](https://github.com/ath3/tree-sitter-passwd) | unstable | `H    ` | @amaanq -[pem](https://github.com/tree-sitter-grammars/tree-sitter-pem) | unstable | `HF J ` | @ObserverOfTime -[perl](https://github.com/tree-sitter-perl/tree-sitter-perl) | unstable | `HF J ` | @RabbiVeesh, @LeoNerd -[php](https://github.com/tree-sitter/tree-sitter-php)[^php] | unstable | `HFIJL` | @tk-shirasaka, @calebdw -[php_only](https://github.com/tree-sitter/tree-sitter-php)[^php_only] | unstable | `HFIJL` | @tk-shirasaka, @calebdw -[phpdoc](https://github.com/claytonrcarter/tree-sitter-phpdoc) | unstable | `H    ` | @mikehaertl -[pioasm](https://github.com/leo60228/tree-sitter-pioasm) | unstable | `H  J ` | @leo60228 -[pkl](https://github.com/apple/tree-sitter-pkl) | unstable | `HF J ` | @ribru17 -[po](https://github.com/tree-sitter-grammars/tree-sitter-po) | unstable | `HF J ` | @amaanq -[pod](https://github.com/tree-sitter-perl/tree-sitter-pod) | unstable | `H    ` | @RabbiVeesh, @LeoNerd -[poe_filter](https://github.com/tree-sitter-grammars/tree-sitter-poe-filter)[^poe_filter] | unstable | `HFIJ ` | @ObserverOfTime -[pony](https://github.com/tree-sitter-grammars/tree-sitter-pony) | unstable | `HFIJL` | @amaanq, @mfelsche -[powershell](https://github.com/airbus-cert/tree-sitter-powershell) | unstable | `HFIJL` | @L2jLiga -[printf](https://github.com/tree-sitter-grammars/tree-sitter-printf) | unstable | `H    ` | @ObserverOfTime -[prisma](https://github.com/victorhqc/tree-sitter-prisma) | unstable | `HF J ` | @elianiva -[problog](https://github.com/foxyseta/tree-sitter-prolog) | unstable | `HFIJ ` | @foxyseta -[prolog](https://github.com/foxyseta/tree-sitter-prolog) | unstable | `HFIJ ` | @foxyseta -[promql](https://github.com/MichaHoffmann/tree-sitter-promql) | unstable | `H  J ` | @MichaHoffmann -[properties](https://github.com/tree-sitter-grammars/tree-sitter-properties)[^properties] | unstable | `H  JL` | @ObserverOfTime -[proto](https://github.com/coder3101/tree-sitter-proto) | unstable | `HFIJ ` | @stefanvanburen -[prql](https://github.com/PRQL/tree-sitter-prql) | unstable | `H  J ` | @matthias-Q -[psv](https://github.com/tree-sitter-grammars/tree-sitter-csv) | unstable | `H    ` | @amaanq -[pug](https://github.com/zealot128/tree-sitter-pug) | unstable | `H  J ` | @zealot128 -[puppet](https://github.com/tree-sitter-grammars/tree-sitter-puppet) | unstable | `HFIJL` | @amaanq -[purescript](https://github.com/postsolar/tree-sitter-purescript) | unstable | `H  JL` | @postsolar -[pymanifest](https://github.com/tree-sitter-grammars/tree-sitter-pymanifest) | unstable | `H  J ` | @ObserverOfTime -[python](https://github.com/tree-sitter/tree-sitter-python) | stable | `HFIJL` | @stsewd, @theHamsta -[ql](https://github.com/tree-sitter/tree-sitter-ql) | unstable | `HFIJL` | @pwntester -[qmldir](https://github.com/tree-sitter-grammars/tree-sitter-qmldir) | unstable | `H  J ` | @amaanq -[qmljs](https://github.com/yuja/tree-sitter-qmljs) | unstable | `HF J ` | @Decodetalkers -[query](https://github.com/tree-sitter-grammars/tree-sitter-query)[^query] | unstable | `HFIJL` | @steelsojka -[r](https://github.com/r-lib/tree-sitter-r) | unstable | `H IJL` | @ribru17 -[racket](https://github.com/6cdh/tree-sitter-racket) | unstable | `HF J ` | -[ralph](https://github.com/alephium/tree-sitter-ralph) | unstable | `H  J ` | @tdroxler -[rasi](https://github.com/Fymyte/tree-sitter-rasi) | unstable | `HFIJL` | @Fymyte -[razor](https://github.com/tris203/tree-sitter-razor) | unstable | `HF J ` | @tris203 -[rbs](https://github.com/joker1007/tree-sitter-rbs) | unstable | `HFIJ ` | @joker1007 -[re2c](https://github.com/tree-sitter-grammars/tree-sitter-re2c) | unstable | `HFIJL` | @amaanq -[readline](https://github.com/tree-sitter-grammars/tree-sitter-readline) | unstable | `HFIJ ` | @ribru17 -[regex](https://github.com/tree-sitter/tree-sitter-regex) | unstable | `H    ` | @theHamsta -[rego](https://github.com/FallenAngel97/tree-sitter-rego) | unstable | `H  J ` | @FallenAngel97 -[requirements](https://github.com/tree-sitter-grammars/tree-sitter-requirements) | unstable | `H  J ` | @ObserverOfTime -[rescript](https://github.com/rescript-lang/tree-sitter-rescript) | unstable | `HFIJL` | @ribru17 -[rifleconf](https://github.com/purarue/tree-sitter-rifleconf) | unstable | `H  J ` | @purarue -[rnoweb](https://github.com/bamonroe/tree-sitter-rnoweb) | unstable | `HF J ` | @bamonroe -[robot](https://github.com/Hubro/tree-sitter-robot) | unmaintained | `HFIJ ` | -[robots_txt](https://github.com/opa-oz/tree-sitter-robots-txt) | unstable | `H  J ` | @opa-oz -[roc](https://github.com/faldor20/tree-sitter-roc) | unmaintained | `H IJL` | -[ron](https://github.com/tree-sitter-grammars/tree-sitter-ron) | unstable | `HFIJL` | @amaanq -[rst](https://github.com/stsewd/tree-sitter-rst) | unstable | `H  JL` | @stsewd -[ruby](https://github.com/tree-sitter/tree-sitter-ruby) | unstable | `HFIJL` | @TravonteD -[runescript](https://github.com/2004Scape/tree-sitter-runescript) | unstable | `H  J ` | @2004Scape -[rust](https://github.com/tree-sitter/tree-sitter-rust) | unstable | `HFIJL` | @amaanq -[scala](https://github.com/tree-sitter/tree-sitter-scala) | unstable | `HF JL` | @stevanmilic -[scfg](https://github.com/rockorager/tree-sitter-scfg) | unstable | `H  J ` | @WhyNotHugo -[scheme](https://github.com/6cdh/tree-sitter-scheme) | unstable | `HF J ` | -[scss](https://github.com/serenadeai/tree-sitter-scss) | unstable | `HFIJ ` | @elianiva -[sflog](https://github.com/aheber/tree-sitter-sfapex)[^sflog] | unstable | `H    ` | @aheber, @xixiaofinland -[slang](https://github.com/tree-sitter-grammars/tree-sitter-slang)[^slang] | unstable | `HFIJL` | @theHamsta -[slim](https://github.com/theoo/tree-sitter-slim) | unstable | `HFIJL` | @theoo -[slint](https://github.com/slint-ui/tree-sitter-slint) | unstable | `HFIJL` | @hunger -[smali](https://github.com/tree-sitter-grammars/tree-sitter-smali) | unstable | `HFIJL` | @amaanq -[smithy](https://github.com/indoorvivants/tree-sitter-smithy) | unstable | `H  J ` | @amaanq, @keynmol -[snakemake](https://github.com/osthomas/tree-sitter-snakemake) | unstable | `HFIJL` | @osthomas -[snl](https://github.com/minijackson/tree-sitter-snl)[^snl] | unstable | `HFIJL` | @minijackson -[solidity](https://github.com/JoranHonig/tree-sitter-solidity) | unstable | `HF J ` | @amaanq -[soql](https://github.com/aheber/tree-sitter-sfapex) | unstable | `H    ` | @aheber, @xixiafinland -[sosl](https://github.com/aheber/tree-sitter-sfapex) | unstable | `H    ` | @aheber, @xixiafinland -[sourcepawn](https://github.com/nilshelmig/tree-sitter-sourcepawn) | unstable | `H  JL` | @Sarrus1 -[sparql](https://github.com/GordianDziwis/tree-sitter-sparql) | unstable | `HFIJL` | @GordianDziwis -[sproto](https://github.com/hanxi/tree-sitter-sproto) | unstable | `HFIJ ` | @hanxi -[sql](https://github.com/derekstride/tree-sitter-sql) | unstable | `HFIJ ` | @derekstride -[squirrel](https://github.com/tree-sitter-grammars/tree-sitter-squirrel) | unstable | `HFIJL` | @amaanq -[ssh_config](https://github.com/tree-sitter-grammars/tree-sitter-ssh-config) | unstable | `HFIJL` | @ObserverOfTime -[starlark](https://github.com/tree-sitter-grammars/tree-sitter-starlark) | unstable | `HFIJL` | @amaanq -[strace](https://github.com/sigmaSd/tree-sitter-strace) | unstable | `H  J ` | @amaanq -[styled](https://github.com/mskelton/tree-sitter-styled) | unstable | `HFIJ ` | @mskelton -[supercollider](https://github.com/madskjeldgaard/tree-sitter-supercollider) | unstable | `HFIJL` | @madskjeldgaard, @elgiano -[superhtml](https://github.com/kristoff-it/superhtml) | unstable | `H  J ` | @rockorager -[surface](https://github.com/connorlay/tree-sitter-surface) | unstable | `HFIJ ` | @connorlay -[svelte](https://github.com/tree-sitter-grammars/tree-sitter-svelte) | unstable | `HFIJL` | @amaanq -[sway](https://github.com/FuelLabs/tree-sitter-sway.git) | unstable | `HFIJL` | @ribru17 -[swift](https://github.com/alex-pinkus/tree-sitter-swift) | unstable | `HFIJL` | @alex-pinkus -[sxhkdrc](https://github.com/RaafatTurki/tree-sitter-sxhkdrc) | unstable | `HF J ` | @RaafatTurki -[systemtap](https://github.com/ok-ryoko/tree-sitter-systemtap) | unstable | `HF JL` | @ok-ryoko -[systemverilog](https://github.com/gmlarumbe/tree-sitter-systemverilog) | unstable | `HF J ` | @zhangwwpeng -[t32](https://github.com/xasc/tree-sitter-t32) | unstable | `HFIJL` | @xasc -[tablegen](https://github.com/tree-sitter-grammars/tree-sitter-tablegen) | unstable | `HFIJL` | @amaanq -[tact](https://github.com/tact-lang/tree-sitter-tact) | unstable | `HFIJL` | @novusnota -[tcl](https://github.com/tree-sitter-grammars/tree-sitter-tcl) | unstable | `HFIJ ` | @lewis6991 -[teal](https://github.com/euclidianAce/tree-sitter-teal) | unstable | `HFIJL` | @euclidianAce -[templ](https://github.com/vrischmann/tree-sitter-templ) | unstable | `HF J ` | @vrischmann -[tera](https://github.com/uncenter/tree-sitter-tera) | unstable | `H  J ` | @uncenter -[terraform](https://github.com/MichaHoffmann/tree-sitter-hcl) | unstable | `HFIJ ` | @MichaHoffmann -[textproto](https://github.com/PorterAtGoogle/tree-sitter-textproto) | unstable | `HFIJ ` | @Porter -[thrift](https://github.com/tree-sitter-grammars/tree-sitter-thrift) | unstable | `HFIJL` | @amaanq, @duskmoon314 -[tiger](https://github.com/ambroisie/tree-sitter-tiger) | unstable | `HFIJL` | @ambroisie -[tlaplus](https://github.com/tlaplus-community/tree-sitter-tlaplus) | unstable | `HF JL` | @ahelwer, @susliko -[tmux](https://github.com/Freed-Wu/tree-sitter-tmux) | unstable | `H  J ` | @Freed-Wu, @stevenxxiu -[todotxt](https://github.com/arnarg/tree-sitter-todotxt) | unstable | `H    ` | @arnarg -[toml](https://github.com/tree-sitter-grammars/tree-sitter-toml) | unstable | `HFIJL` | @tk-shirasaka -[tsv](https://github.com/tree-sitter-grammars/tree-sitter-csv) | unstable | `H    ` | @amaanq -[tsx](https://github.com/tree-sitter/tree-sitter-typescript) | unstable | `HFIJL` | @steelsojka -[turtle](https://github.com/GordianDziwis/tree-sitter-turtle) | unstable | `HFIJL` | @GordianDziwis -[twig](https://github.com/gbprod/tree-sitter-twig) | unstable | `H  J ` | @gbprod -[typescript](https://github.com/tree-sitter/tree-sitter-typescript) | unstable | `HFIJL` | @steelsojka -[typespec](https://github.com/happenslol/tree-sitter-typespec) | unstable | `H IJ ` | @happenslol -[typoscript](https://github.com/Teddytrombone/tree-sitter-typoscript) | unstable | `HFIJ ` | @Teddytrombone -[typst](https://github.com/uben0/tree-sitter-typst) | unstable | `HFIJ ` | @uben0, @RaafatTurki -[udev](https://github.com/tree-sitter-grammars/tree-sitter-udev) | unstable | `H  JL` | @ObserverOfTime -[ungrammar](https://github.com/tree-sitter-grammars/tree-sitter-ungrammar) | unstable | `HFIJL` | @Philipp-M, @amaanq -[unison](https://github.com/kylegoetz/tree-sitter-unison) | unstable | `HF J ` | @tapegram -[usd](https://github.com/ColinKennedy/tree-sitter-usd) | unstable | `HFIJL` | @ColinKennedy -[uxntal](https://github.com/tree-sitter-grammars/tree-sitter-uxntal) | unstable | `HFIJL` | @amaanq -[v](https://github.com/vlang/v-analyzer) | unstable | `HFIJL` | @kkharji, @amaanq -[vala](https://github.com/vala-lang/tree-sitter-vala) | unstable | `HF J ` | @Prince781 -[vento](https://github.com/ventojs/tree-sitter-vento) | unmaintained | `H  J ` | -[vhdl](https://github.com/jpt13653903/tree-sitter-vhdl) | unstable | `HF J ` | @jpt13653903 -[vhs](https://github.com/charmbracelet/tree-sitter-vhs) | unstable | `H  J ` | @caarlos0 -[vim](https://github.com/tree-sitter-grammars/tree-sitter-vim) | unstable | `HF JL` | @clason -[vimdoc](https://github.com/neovim/tree-sitter-vimdoc) | unstable | `H  J ` | @clason -[vrl](https://github.com/belltoy/tree-sitter-vrl) | unstable | `HFIJL` | @belltoy -[vue](https://github.com/tree-sitter-grammars/tree-sitter-vue) | unstable | `HFIJ ` | @WhyNotHugo, @lucario387 -[wgsl](https://github.com/szebniok/tree-sitter-wgsl) | unstable | `HFIJ ` | @szebniok -[wgsl_bevy](https://github.com/tree-sitter-grammars/tree-sitter-wgsl-bevy) | unstable | `HFI  ` | @theHamsta -[wing](https://github.com/winglang/tree-sitter-wing) | unstable | `HF JL` | @gshpychka, @MarkMcCulloh -[wit](https://github.com/bytecodealliance/tree-sitter-wit) | stable | `HF J ` | @mkatychev -[wxml](https://github.com/BlockLune/tree-sitter-wxml) | unstable | `HFIJ ` | @BlockLune -[xcompose](https://github.com/tree-sitter-grammars/tree-sitter-xcompose) | unstable | `H  JL` | @ObserverOfTime -[xml](https://github.com/tree-sitter-grammars/tree-sitter-xml) | unstable | `HFIJL` | @ObserverOfTime -[xresources](https://github.com/ValdezFOmar/tree-sitter-xresources) | stable | `HF JL` | @ValdezFOmar -[yaml](https://github.com/tree-sitter-grammars/tree-sitter-yaml) | unstable | `HFIJL` | @amaanq -[yang](https://github.com/Hubro/tree-sitter-yang) | unstable | `HFIJ ` | @Hubro -[yuck](https://github.com/tree-sitter-grammars/tree-sitter-yuck) | unstable | `HFIJL` | @Philipp-M, @amaanq -[zathurarc](https://github.com/Freed-Wu/tree-sitter-zathurarc) | unstable | `H  J ` | @Freed-Wu -[zig](https://github.com/tree-sitter-grammars/tree-sitter-zig) | unstable | `HFIJL` | @amaanq -[ziggy](https://github.com/kristoff-it/ziggy) | unmaintained | `H I  ` | -[ziggy_schema](https://github.com/kristoff-it/ziggy) | unmaintained | `H I  ` | -[zsh](https://github.com/georgeharker/tree-sitter-zsh) | unstable | `HF JL` | @georgeharker -[^bp]: Android Blueprint -[^ecma]: queries required by javascript, typescript, tsx, qmljs -[^gap]: GAP system -[^gaptst]: GAP system test files -[^gdscript]: Godot -[^glimmer]: Glimmer and Ember -[^godot_resource]: Godot Resources -[^html_tags]: queries required by html, astro, vue, svelte -[^jinja]: basic highlighting -[^jinja_inline]: needed for full highlighting -[^jsx]: queries required by javascript, tsx -[^luap]: Lua patterns -[^markdown]: basic highlighting -[^markdown_inline]: needed for full highlighting -[^php]: PHP with embedded HTML -[^php_only]: PHP without embedded HTML -[^poe_filter]: Path of Exile item filter -[^properties]: Java properties files -[^query]: Tree-sitter query language -[^sflog]: Salesforce debug log -[^slang]: Shader Slang -[^snl]: EPICS Sequencer's SNL files - diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 000000000..a60e536bc Binary files /dev/null and b/assets/logo.png differ diff --git a/autoload/nvim_treesitter.vim b/autoload/nvim_treesitter.vim new file mode 100644 index 000000000..90953985e --- /dev/null +++ b/autoload/nvim_treesitter.vim @@ -0,0 +1,27 @@ +function! nvim_treesitter#statusline(...) abort + return luaeval("require'nvim-treesitter.statusline'.statusline(_A)", get(a:, 1, {})) +endfunction + +function! nvim_treesitter#foldexpr() abort + return luaeval(printf('require"nvim-treesitter.fold".get_fold_indic(%d)', v:lnum)) +endfunction + +function! nvim_treesitter#installable_parsers(arglead, cmdline, cursorpos) abort + return join(luaeval("require'nvim-treesitter.parsers'.available_parsers()") + ['all'], "\n") +endfunction + +function! nvim_treesitter#installed_parsers(arglead, cmdline, cursorpos) abort + return join(luaeval("require'nvim-treesitter.info'.installed_parsers()") + ['all'], "\n") +endfunction + +function! nvim_treesitter#available_modules(arglead, cmdline, cursorpos) abort + return join(luaeval("require'nvim-treesitter.configs'.available_modules()"), "\n") +endfunction + +function! nvim_treesitter#available_query_groups(arglead, cmdline, cursorpos) abort + return join(luaeval("require'nvim-treesitter.query'.available_query_groups()"), "\n") +endfunction + +function! nvim_treesitter#indent() abort + return luaeval(printf('require"nvim-treesitter.indent".get_indent(%d)', v:lnum)) +endfunction diff --git a/contrib/nvim-treesitter-scm-1.rockspec b/contrib/nvim-treesitter-scm-1.rockspec new file mode 100644 index 000000000..cacc9eb2e --- /dev/null +++ b/contrib/nvim-treesitter-scm-1.rockspec @@ -0,0 +1,32 @@ +local MODREV, SPECREV = "scm", "-1" +rockspec_format = "3.0" +package = "nvim-treesitter" +version = MODREV .. SPECREV + +description = { + summary = "Nvim Treesitter configurations and abstraction layer", + labels = { "neovim"}, + homepage = "https://github.com/nvim-treesitter/nvim-treesitter", + license = "Apache-2.0", +} + +dependencies = { + "lua >= 5.1, < 5.4", +} + +source = { + url = "http://github.com/nvim-treesitter/nvim-treesitter/archive/v" .. MODREV .. ".zip", +} + +if MODREV == 'scm' then + source = { + url = 'git://github.com/nvim-treesitter/nvim-treesitter', + } +end + +build = { + type = "builtin", + copy_directories = { + 'plugin' + } +} diff --git a/doc/nvim-treesitter.txt b/doc/nvim-treesitter.txt index e6a67f398..4feabb739 100644 --- a/doc/nvim-treesitter.txt +++ b/doc/nvim-treesitter.txt @@ -1,4 +1,6 @@ -*nvim-treesitter.txt* Treesitter parser and query installer for Neovim +*nvim-treesitter* Treesitter configurations and abstraction layer for Neovim. + +Minimum version of neovim: nightly Authors: Kiyan Yazdani @@ -11,179 +13,475 @@ Authors: Type |gO| to see the table of contents. ============================================================================== -INTRODUCTION *nvim-treesitter-intro* +INTRODUCTION *nvim-treesitter-intro* -Nvim-treesitter provides functionalities for managing treesitter parsers and -compatible queries for core features (highlighting, injections, folds, -indents). +nvim-treesitter wraps the Neovim treesitter API to provide functionalities +such as highlighting and incremental selection, and a command to easily +install parsers. ============================================================================== -QUICK START *nvim-treesitter-quickstart* +QUICK START *nvim-treesitter-quickstart* -To configure `nvim-treesitter`, put this in your `init.lua` file: ->lua - require'nvim-treesitter'.setup { - -- A directory to install the parsers and queries to. - -- Defaults to the `stdpath('data')/site` dir. - install_dir = "/some/path/to/store/parsers", +Install the parser for your language + +> + :TSInstall {language} +< + +To get a list of supported languages + +> + :TSInstallInfo +< + +By default, everything is disabled. +To enable supported features, put this in your `init.lua` file: + +> + require'nvim-treesitter.configs'.setup { + -- A directory to install the parsers into. + -- If this is excluded or nil parsers are installed + -- to either the package dir, or the "site" dir. + -- If a custom path is used (not nil) it must be added to the runtimepath. + parser_install_dir = "/some/path/to/store/parsers", + + -- A list of parser names, or "all" + ensure_installed = { "c", "lua", "rust" }, + + -- Install parsers synchronously (only applied to `ensure_installed`) + sync_install = false, + + -- Automatically install missing parsers when entering buffer + auto_install = false, + + -- List of parsers to ignore installing (for "all") + ignore_install = { "javascript" }, + + highlight = { + -- `false` will disable the whole extension + enable = true, + + -- list of language that will be disabled + disable = { "c", "rust" }, + + -- Setting this to true will run `:h syntax` and tree-sitter at the same time. + -- Set this to `true` if you depend on 'syntax' being enabled (like for indentation). + -- Using this option may slow down your editor, and you may see some duplicate highlights. + -- Instead of true it can also be a list of languages + additional_vim_regex_highlighting = false, + }, } - -NOTE: You do not need to call `setup` to use this plugin with the default -settings! - -Parsers and queries can then be installed with >lua - require'nvim-treesitter'.install { 'rust', 'javascript', 'zig' } + vim.opt.runtimepath:append("/some/path/to/store/parsers") < -To check installed parsers and queries, use `:checkhealth nvim-treesitter`. -Treesitter features for installed languages need to be enabled manually in a -|FileType| autocommand or |ftplugin|, e.g. >lua - vim.api.nvim_create_autocmd('FileType', { - pattern = { 'rust', 'javascript', 'zig' }, - callback = function() - -- syntax highlighting, provided by Neovim - vim.treesitter.start() - -- folds, provided by Neovim - vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()' - vim.wo.foldmethod = 'expr' - -- indentation, provided by nvim-treesitter - vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" - end, - }) -< -============================================================================== -COMMANDS *nvim-treesitter-commands* - -:TSInstall {language} *:TSInstall* - -Install one or more treesitter parsers. {language} can be one or multiple -parsers or tiers (`stable`, `unstable`, or `all` (not recommended)). This is a -no-op if the parser(s) are already installed. Installation is performed -asynchronously. Use *:TSInstall!* to force installation even if a parser is -already installed. - -:TSInstallFromGrammar {language} *:TSInstallFromGrammar* - -Like |:TSInstall| but also regenerates the `parser.c` from the original -grammar. Useful for languages where the provided `parser.c` is outdated (e.g., -uses a no longer supported ABI). - -:TSUpdate [{language}] *:TSUpdate* - -Update parsers to the `revision` specified in the manifest if this is newer -than the installed version. If {language} is specified, update the -corresponding parser or tier; otherwise update all installed parsers. This is -a no-op if all (specified) parsers are up to date. - -Note: It is recommended to add this command as a build step in your plugin -manager. - -:TSUninstall {language} *:TSUninstall* - -Deletes the parser for one or more {language}, or all parsers with `all`. - -:TSLog *:TSLog* - -Shows all messages from previous install, update, or uninstall operations. +See |nvim-treesitter-modules| for a list of all available modules and its options. ============================================================================== -API *nvim-treesitter-api* +MODULES *nvim-treesitter-modules* -setup({opts}) *nvim-treesitter.setup()* +|nvim-treesitter| provides several functionalities via modules (and submodules), +each module makes use of the query files defined for each language, - Configure installation options. Needs to be specified before any - installation operation. +All modules are disabled by default, and some provide default keymaps. +Each module corresponds to an entry in the dictionary passed to the +`nvim-treesitter.configs.setup` function, this should be in your `init.lua` file. - Note: You only need to call `setup` if you want to set non-default - options! - - Parameters: ~ - • {opts} `(table?)` Optional parameters: - • {install_dir} (`string?`, default `stdpath('data')/site/`) - directory to install parsers and queries to. Note: will be - prepended to |runtimepath|. - -install({languages} [, {opts}]) *nvim-treesitter.install()* - - Download, compile, and install the specified treesitter parsers and copy - the corresponding queries to a directory on |runtimepath|, enabling their - use in Neovim. - - Note: This operation is performed asynchronously by default. For - synchronous operation (e.g., in a bootstrapping script), you need to - `wait()` for it: >lua - require('nvim-treesitter').install({ 'rust', 'javascript', 'zig' }) - :wait(300000) -- max. 5 minutes +> + require'nvim-treesitter.configs'.setup { + -- Modules and its options go here + highlight = { enable = true }, + incremental_selection = { enable = true }, + textobjects = { enable = true }, + } < - Parameters: ~ - • {languages} `(string[]|string)` (List of) languages or tiers (`stable`, - `unstable`) to install. - • {opts} `(table?)` Optional parameters: - • {force} (`boolean?`, default `false`) force installation - of already installed parsers - • {generate} (`boolean?`, default `false`) generate - `parser.c` from `grammar.json` or `grammar.js` before - compiling. - • {max_jobs} (`integer?`) limit parallel tasks (useful in - combination with {generate} on memory-limited systems). - • {summary} (`boolean?`, default `false`) print summary of - successful and total operations for multiple languages. -uninstall({languages} [, {opts}]) *nvim-treesitter.uninstall()* +All modules share some common options, like `enable` and `disable`. +When `enable` is `true` this will enable the module for all supported languages, +if you want to disable the module for some languages you can pass a list to the `disable` option. - Remove the parser and queries for the specified language(s). - - Parameters: ~ - • {languages} `(string[]|string)` (List of) languages or tiers (`stable`, - `unstable`) to update. - • {opts} `(table?)` Optional parameters: - • {summary} (`boolean?`, default `false`) print summary of - successful and total operations for multiple languages. - -update([{languages}, {opts}]) *nvim-treesitter.update()* - - Update the parsers and queries if older than the revision specified in the - manifest. - - Note: This operation is performed asynchronously by default. For - synchronous operation (e.g., in a bootstrapping script), you need to - `wait()` for it: >lua - require('nvim-treesitter').update():wait(300000) -- max. 5 minutes +> + require'nvim-treesitter.configs'.setup { + highlight = { + enable = true, + disable = { "cpp", "lua" }, + }, + } < - Parameters: ~ - • {languages} `(string[]|string)?` (List of) languages or tiers to update - (default: all installed). - • {opts} `(table?)` Optional parameters: - • {max_jobs} (`integer?`) limit parallel tasks (useful in - combination with {generate} on memory-limited systems). - • {summary} (`boolean?`, default `false`) print summary of - successful and total operations for multiple languages. -indentexpr() *nvim-treesitter.indentexpr()* +For more fine-grained control, `disable` can also take a function and +whenever it returns `true`, the module is disabled for that buffer. +The function is called once when a module starts in a buffer and receives the +language and buffer number as arguments: - Used to enable treesitter indentation for a language via >lua - vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" +> + require'nvim-treesitter.configs'.setup { + highlight = { + enable = true, + disable = function(lang, bufnr) -- Disable in large C++ buffers + return lang == "cpp" and vim.api.nvim_buf_line_count(bufnr) > 50000 + end, + }, + } < -get_available([{tier}]) *nvim-treesitter.get_available()* - Return list of languages available for installation. +Options that define or accept a keymap use the same format you use to define +keymaps in Neovim, so you can write keymaps as `gd`, `a`, `a` +`` (control + a), `` (alt + n), `` (enter), etc. - Parameters: ~ - • {tier} `(integer?)` Only return languages of specified {tier} (`1`: - stable, `2`: unstable, `3`: unmaintained, `4`: unsupported) +External plugins can provide their own modules with their own options, +those can also be configured using the `nvim-treesitter.configs.setup` +function. -get_installed([{type}]) *nvim-treesitter.get_installed()* +------------------------------------------------------------------------------ +HIGHLIGHT *nvim-treesitter-highlight-mod* - Return list of languages installed via `nvim-treesitter`. +Consistent syntax highlighting. - Note: This only searches `nvim-treesitter`'s (configured or default) - installation directory; parsers and queries from other sources can be - placed anywhere on 'runtimepath' and are not included. To list all, e.g., - parsers that are installed from any source, use >lua - vim.api.nvim_get_runtime_file('parser/*', true) +Query files: `highlights.scm`. +Supported options: + +- enable: `true` or `false`. +- disable: list of languages. +- additional_vim_regex_highlighting: `true` or `false`, or a list of languages. + Set this to `true` if you depend on 'syntax' being enabled + (like for indentation). Using this option may slow down your editor, + and you may see some duplicate highlights. + Defaults to `false`. + +> + require'nvim-treesitter.configs'.setup { + highlight = { + enable = true, + custom_captures = { + -- Highlight the @foo.bar capture group with the "Identifier" highlight group. + ["foo.bar"] = "Identifier", + }, + -- Setting this to true or a list of languages will run `:h syntax` and tree-sitter at the same time. + additional_vim_regex_highlighting = false, + }, + } < - Parameters: ~ - • {type} `('queries'|parsers'?)` If specified, only show languages with - installed queries or parsers, respectively. + +You can also set custom highlight captures +> + lua < + require'nvim-treesitter.configs'.setup { + incremental_selection = { + enable = true, + keymaps = { + init_selection = "gnn", + node_incremental = "grn", + scope_incremental = "grc", + node_decremental = "grm", + }, + }, + } +< + +------------------------------------------------------------------------------ +INDENTATION *nvim-treesitter-indentation-mod* + +Indentation based on treesitter for the |=| operator. +NOTE: this is an experimental feature. + +Query files: `indents.scm`. +Supported options: +- enable: `true` or `false`. +- disable: list of languages. +> + require'nvim-treesitter.configs'.setup { + indent = { + enable = true + }, + } +< +============================================================================== +COMMANDS *nvim-treesitter-commands* + + *:TSInstall* +:TSInstall {language} ...~ + +Install one or more treesitter parsers. +You can use |:TSInstall| `all` to install all parsers. Use |:TSInstall!| to +force the reinstallation of already installed parsers. + *:TSInstallSync* +:TSInstallSync {language} ...~ + +Perform the |:TSInstall| operation synchronously. + + *:TSInstallInfo* +:TSInstallInfo~ + +List information about currently installed parsers + + *:TSUpdate* +:TSUpdate {language} ...~ + +Update the installed parser for one more {language} or all installed parsers +if {language} is omitted. The specified parser is installed if it is not already +installed. + + *:TSUpdateSync* +:TSUpdateSync {language} ...~ + +Perform the |:TSUpdate| operation synchronously. + + *:TSUninstall* +:TSUninstall {language} ...~ + +Deletes the parser for one or more {language}. You can use 'all' for language +to uninstall all parsers. + + *:TSBufEnable* +:TSBufEnable {module}~ + +Enable {module} on the current buffer. +A list of modules can be found at |:TSModuleInfo| + + *:TSBufDisable* +:TSBufDisable {module}~ + +Disable {module} on the current buffer. +A list of modules can be found at |:TSModuleInfo| + + *:TSBufToggle* +:TSBufToggle {module}~ + +Toggle (enable if disabled, disable if enabled) {module} on the current +buffer. +A list of modules can be found at |:TSModuleInfo| + + *:TSEnable* +:TSEnable {module} [{language}]~ + +Enable {module} for the session. +If {language} is specified, enable module for the session only for this +particular language. +A list of modules can be found at |:TSModuleInfo| +A list of languages can be found at |:TSInstallInfo| + + *:TSDisable* +:TSDisable {module} [{language}]~ + +Disable {module} for the session. +If {language} is specified, disable module for the session only for this +particular language. +A list of modules can be found at |:TSModuleInfo| +A list of languages can be found at |:TSInstallInfo| + + *:TSToggle* +:TSToggle {module} [{language}]~ + +Toggle (enable if disabled, disable if enabled) {module} for the session. +If {language} is specified, toggle module for the session only for this +particular language. +A list of modules can be found at |:TSModuleInfo| +A list of languages can be found at |:TSInstallInfo| + + *:TSModuleInfo* +:TSModuleInfo [{module}]~ + +List the state for the given module or all modules for the current session in +a new buffer. + +These highlight groups are used by default: +> + highlight default TSModuleInfoGood guifg=LightGreen gui=bold + highlight default TSModuleInfoBad guifg=Crimson + highlight default link TSModuleInfoHeader Type + highlight default link TSModuleInfoNamespace Statement + highlight default link TSModuleInfoParser Identifier +< + + *:TSEditQuery* +:TSEditQuery {query-group} [{lang}]~ + +Edit the query file for a {query-group} (e.g. highlights, locals) for given +{lang}. If there are multiple the user is prompted to select one of them. +If no such file exists, a buffer for a new file in the user's config directory +is created. If {lang} is not specified, the language of the current buffer +is used. + + *:TSEditQueryUserAfter* +:TSEditQueryUserAfter {query-group} [{lang}]~ + +Same as |:TSEditQuery| but edits a file in the `after` directory of the +user's config directory. Useful to add custom extensions for the queries +provided by a plugin. + +============================================================================== +UTILS *nvim-treesitter-utils* + +Nvim treesitter has some wrapper functions that you can retrieve with: +> + local ts_utils = require 'nvim-treesitter.ts_utils' +< +Methods + *ts_utils.get_node_at_cursor* +get_node_at_cursor(winnr)~ + +`winnr` will be 0 if nil. +Returns the node under the cursor. + + *ts_utils.is_parent* +is_parent(dest, source)~ + +Determines whether `dest` is a parent of `source`. +Returns a boolean. + + *ts_utils.get_named_children* +get_named_children(node)~ + +Returns a table of named children of `node`. + + *ts_utils.get_next_node* +get_next_node(node, allow_switch_parent, allow_next_parent)~ + +Returns the next node within the same parent. +If no node is found, returns `nil`. +If `allow_switch_parent` is true, it will allow switching parent +when the node is the last node. +If `allow_next_parent` is true, it will allow next parent if +the node is the last node and the next parent doesn't have children. + + *ts_utils.get_previous_node* +get_previous_node(node, allow_switch_parents, allow_prev_parent)~ + +Returns the previous node within the same parent. +`allow_switch_parent` and `allow_prev_parent` follow the same rule +as |ts_utils.get_next_node| but if the node is the first node. + + *ts_utils.goto_node* +goto_node(node, goto_end, avoid_set_jump)~ + +Sets cursor to the position of `node` in the current windows. +If `goto_end` is truthy, the cursor is set to the end the node range. +Setting `avoid_set_jump` to `true`, avoids setting the current cursor position +to the jump list. + + *ts_utils.swap_nodes* +swap_nodes(node_or_range1, node_or_range2, bufnr, cursor_to_second)~ + +Swaps the nodes or ranges. +set `cursor_to_second` to true to move the cursor to the second node + + *ts_utils.memoize_by_buf_tick* +memoize_by_buf_tick(fn, options)~ + +Caches the return value for a function and returns the cache value if the tick +of the buffer has not changed from the previous. + + `fn`: a function that takes any arguments + and returns a value to store. + `options?`: + - `bufnr`: a function/value that extracts the bufnr from the given arguments. + - `key`: a function/value that extracts the cache key from the given arguments. + `returns`: a function to call with bufnr as argument to + retrieve the value from the cache + + *ts_utils.node_to_lsp_range* +node_to_lsp_range(node)~ + +Get an lsp formatted range from a node range + + *ts_utils.get_node_range* +get_node_range(node_or_range)~ + +Get the range from either a node or a range + + *ts_utils.node_length* +node_length(node)~ + +Get the byte length of node range + + *ts_utils.update_selection* +update_selection(buf, node)~ + +Set the selection to the node range + + *ts_utils.highlight_range* +highlight_range(range, buf, hl_namespace, hl_group)~ + +Set a highlight that spans the given range + + *ts_utils.highlight_node* +highlight_node(node, buf, hl_namespace, hl_group)~ + +Set a highlight that spans the given node's range + +============================================================================== +FUNCTIONS *nvim-treesitter-functions* + + *nvim_treesitter#statusline()* +nvim_treesitter#statusline(opts)~ + +Returns a string describing the current position in the file. This +could be used as a statusline indicator. +Default options (lua syntax): +> + { + indicator_size = 100, + type_patterns = {'class', 'function', 'method'}, + transform_fn = function(line) return line:gsub('%s*[%[%(%{]*%s*$', '') end, + separator = ' -> ' + } +< +- `indicator_size` - How long should the string be. If longer, it is cut from + the beginning. +- `type_patterns` - Which node type patterns to match. +- `transform_fn` - Function used to transform the single item in line. By + default removes opening brackets and spaces from end. +- `separator` - Separator between nodes. + + *nvim_treesitter#foldexpr()* +nvim_treesitter#foldexpr()~ + +Functions to be used to determine the fold level at a given line number. +To use it: > + set foldmethod=expr + set foldexpr=nvim_treesitter#foldexpr() +< + +This will respect your 'foldminlines' and 'foldnestmax' settings. + +Note: This is highly experimental, and folding can break on some types of + edits. If you encounter such breakage, hiting `zx` should fix folding. + In any case, feel free to open an issue with the reproducing steps. + +============================================================================== +PERFORMANCE *nvim-treesitter-performance* + +`nvim-treesitter` checks the 'runtimepath' on startup in order to discover +available parsers and queries and index them. As a consequence, a very long +'runtimepath' might result in delayed startup times. + vim:tw=78:ts=8:expandtab:noet:ft=help:norl: diff --git a/lockfile.json b/lockfile.json new file mode 100644 index 000000000..201c0c8db --- /dev/null +++ b/lockfile.json @@ -0,0 +1,425 @@ +{ + "agda": { + "revision": "80ea622cf952a0059e168e5c92a798b2f1925652" + }, + "arduino": { + "revision": "c473c09f23b13d9404ec5208fad3eddea89d70f8" + }, + "astro": { + "revision": "947e93089e60c66e681eba22283f4037841451e7" + }, + "awk": { + "revision": "e559793754c60c2cdf00cbb0409842d75f0a41dc" + }, + "bash": { + "revision": "4488aa41406547e478636a4fcfd24f5bbc3f2f74" + }, + "beancount": { + "revision": "4cbd1f09cd07c1f1fabf867c2cf354f9da53cc4c" + }, + "bibtex": { + "revision": "ccfd77db0ed799b6c22c214fe9d2937f47bc8b34" + }, + "blueprint": { + "revision": "6ef91ca8270f0112b9c6d27ecb9966c741a5d103" + }, + "c": { + "revision": "7175a6dd5fc1cee660dce6fe23f6043d75af424a" + }, + "c_sharp": { + "revision": "3ef3f7f99e16e528e6689eae44dff35150993307" + }, + "clojure": { + "revision": "8c23e0ec078af461ccad43fffbbfc204aa6bc238" + }, + "cmake": { + "revision": "a32265307aa2d31941056d69e8b6633e61750b2f" + }, + "comment": { + "revision": "a37ca370310ac6f89b6e0ebf2b86b2219780494e" + }, + "commonlisp": { + "revision": "c7e814975ab0d0d04333d1f32391c41180c58919" + }, + "cooklang": { + "revision": "5e113412aadb78955c27010daa4dbe1d202013cf" + }, + "cpp": { + "revision": "5ead1e26c6ab71919db0f1880c46a278a93bc5ea" + }, + "css": { + "revision": "769203d0f9abe1a9a691ac2b9fe4bb4397a73c51" + }, + "cuda": { + "revision": "7f1a79e612160aa02be87f1a24469ae3655fe818" + }, + "d": { + "revision": "c2fbf21bd3aa45495fe13247e040ad5815250032" + }, + "dart": { + "revision": "53485a8f301254e19c518aa20c80f1bcf7cf5c62" + }, + "devicetree": { + "revision": "ea30a05d0f0446a96d8b096ad11828ad4f8ad849" + }, + "diff": { + "revision": "1d63cd49529ef3153393cf8f620718b274bba715" + }, + "dockerfile": { + "revision": "09e316dba307b869831e9399b11a83bbf0f2a24b" + }, + "dot": { + "revision": "9ab85550c896d8b294d9b9ca1e30698736f08cea" + }, + "ebnf": { + "revision": "ef241bc09f2f105c35f5e4f2ccd8a522dd99071c" + }, + "eex": { + "revision": "f742f2fe327463335e8671a87c0b9b396905d1d1" + }, + "elixir": { + "revision": "b20eaa75565243c50be5e35e253d8beb58f45d56" + }, + "elm": { + "revision": "28bb193640d916dfaf947912c1413cebb0484841" + }, + "elvish": { + "revision": "f32711e31e987fd5c2c002f3daba02f25c68672f" + }, + "embedded_template": { + "revision": "91fc5ae1140d5c9d922312431f7d251a48d7b8ce" + }, + "erlang": { + "revision": "a8b8b0e16c4f5552f5e85af3dec976a5d16af8b9" + }, + "fennel": { + "revision": "517195970428aacca60891b050aa53eabf4ba78d" + }, + "fish": { + "revision": "6675b56266b3f615fb112205b6b83a79315309c4" + }, + "foam": { + "revision": "c238f4af9a5723a212cf1a4c9b31dd5c1d5270a2" + }, + "fortran": { + "revision": "f0f2f100952a353e64e26b0fa710b4c296d7af13" + }, + "fusion": { + "revision": "19db2f47ba4c3a0f6238d4ae0e2abfca16e61dd6" + }, + "gdscript": { + "revision": "2a6abdaa47fcb91397e09a97c7433fd995ea46c6" + }, + "git_rebase": { + "revision": "127f5b56c1ad3e8a449a7d6e0c7412ead7f7724c" + }, + "gitattributes": { + "revision": "577a075d46ea109905c5cb6179809df88da61ce9" + }, + "gitcommit": { + "revision": "f838621d00831967a39ac8293cd3c23b0f49252e" + }, + "gitignore": { + "revision": "f4685bf11ac466dd278449bcfe5fd014e94aa504" + }, + "gleam": { + "revision": "cfcbca3f8f734773878e00d7bfcedea98eb10be2" + }, + "glimmer": { + "revision": "fee34278dc212869dcfc92fce3007ee79a752867" + }, + "glsl": { + "revision": "e2c2214045de2628b81089b1a739962f59654558" + }, + "go": { + "revision": "64457ea6b73ef5422ed1687178d4545c3e91334a" + }, + "godot_resource": { + "revision": "b6ef0768711086a86b3297056f9ffb5cc1d77b4a" + }, + "gomod": { + "revision": "4a65743dbc2bb3094114dd2b43da03c820aa5234" + }, + "gowork": { + "revision": "949a8a470559543857a62102c84700d291fc984c" + }, + "graphql": { + "revision": "5e66e961eee421786bdda8495ed1db045e06b5fe" + }, + "hack": { + "revision": "b7bd6928532ada34dddb1dece4a158ab62c6e783" + }, + "haskell": { + "revision": "aee3725d02cf3bca5f307b35dd3a96a97e109b4e" + }, + "hcl": { + "revision": "0ff887f2a60a147452d52db060de6b42f42f1441" + }, + "heex": { + "revision": "2e1348c3cf2c9323e87c2744796cf3f3868aa82a" + }, + "help": { + "revision": "ce20f13c3f12506185754888feaae3f2ad54c287" + }, + "hjson": { + "revision": "02fa3b79b3ff9a296066da6277adfc3f26cbc9e0" + }, + "hlsl": { + "revision": "329e3c8bd6f696a6128e0dccba34b2799dc3037e" + }, + "hocon": { + "revision": "c390f10519ae69fdb03b3e5764f5592fb6924bcc" + }, + "html": { + "revision": "29f53d8f4f2335e61bf6418ab8958dac3282077a" + }, + "http": { + "revision": "30a9c1789d64429a830802cde5b1760ff1064312" + }, + "java": { + "revision": "09d650def6cdf7f479f4b78f595e9ef5b58ce31e" + }, + "javascript": { + "revision": "7a29d06274b7cf87d643212a433d970b73969016" + }, + "jq": { + "revision": "13990f530e8e6709b7978503da9bc8701d366791" + }, + "jsdoc": { + "revision": "189a6a4829beb9cdbe837260653b4a3dfb0cc3db" + }, + "json": { + "revision": "73076754005a460947cafe8e03a8cf5fa4fa2938" + }, + "json5": { + "revision": "5dd5cdc418d9659682556b6adca2dd9ace0ac6d2" + }, + "jsonc": { + "revision": "02b01653c8a1c198ae7287d566efa86a135b30d5" + }, + "jsonnet": { + "revision": "44c0d58dfb523b7f1066ef4013cc543afc696960" + }, + "julia": { + "revision": "91ba1c3c9b50f388d4b67518c04bc9a003ed3475" + }, + "kotlin": { + "revision": "b953dbdd05257fcb2b64bc4d9c1578fac12e3c28" + }, + "lalrpop": { + "revision": "7744b56f03ac1e5643fad23c9dd90837fe97291e" + }, + "latex": { + "revision": "1ec3941b971dccfa36cb1cd6221a2e4a1cd3e250" + }, + "ledger": { + "revision": "47b8971448ce5e9abac865f450c1b14fb3b6eee9" + }, + "llvm": { + "revision": "e9948edc41e9e5869af99dddb2b5ff5cc5581af6" + }, + "lua": { + "revision": "f5e84ffc2b06858401e0d2edf5dce009efbe34b3" + }, + "m68k": { + "revision": "d097b123f19c6eaba2bf181c05420d88b9fc489d" + }, + "make": { + "revision": "a4b9187417d6be349ee5fd4b6e77b4172c6827dd" + }, + "markdown": { + "revision": "16d0b5e54d781150bea1070ffb360d47e6238659" + }, + "markdown_inline": { + "revision": "16d0b5e54d781150bea1070ffb360d47e6238659" + }, + "menhir": { + "revision": "db7953acb0d5551f207373c81fa07a57d7b085cb" + }, + "mermaid": { + "revision": "d787c66276e7e95899230539f556e8b83ee16f6d" + }, + "meson": { + "revision": "6c5f7ef944f9c6ae8a0fc28b9071a4b493652238" + }, + "nickel": { + "revision": "9d83db400b6c11260b9106f131f93ddda8131933" + }, + "ninja": { + "revision": "0a95cfdc0745b6ae82f60d3a339b37f19b7b9267" + }, + "nix": { + "revision": "6b71a810c0acd49b980c50fc79092561f7cee307" + }, + "norg": { + "revision": "8ad20059c6f128861c4506fff866150ffee1d6f4" + }, + "ocaml": { + "revision": "cc26b1ef111100f26a137bcbcd39fd4e35be9a59" + }, + "ocaml_interface": { + "revision": "cc26b1ef111100f26a137bcbcd39fd4e35be9a59" + }, + "ocamllex": { + "revision": "ac1d5957e719d49bd6acd27439b79843e4daf8ed" + }, + "org": { + "revision": "081179c52b3e8175af62b9b91dc099d010c38770" + }, + "pascal": { + "revision": "9e995404ddff8319631d72d4b46552e737206912" + }, + "perl": { + "revision": "749d26fe13fb131b92e6515416096e572575b981" + }, + "php": { + "revision": "680244ac3a8092154125e91145fe8d631cd4583b" + }, + "phpdoc": { + "revision": "2f4d16c861b5a454b577d057f247f9902d7b47f5" + }, + "pioasm": { + "revision": "924aadaf5dea2a6074d72027b064f939acf32e20" + }, + "prisma": { + "revision": "17a59236ac25413b81b1613ea6ba5d8d52d7cd6c" + }, + "proto": { + "revision": "42d82fa18f8afe59b5fc0b16c207ee4f84cb185f" + }, + "pug": { + "revision": "63e214905970e75f065688b1e8aa90823c3aacdc" + }, + "python": { + "revision": "9e53981ec31b789ee26162ea335de71f02186003" + }, + "ql": { + "revision": "bd087020f0d8c183080ca615d38de0ec827aeeaf" + }, + "qmljs": { + "revision": "0b2b25bcaa7d4925d5f0dda16f6a99c588a437f1" + }, + "query": { + "revision": "0695cd0760532de7b54f23c667d459b5d1332b44" + }, + "r": { + "revision": "80efda55672d1293aa738f956c7ae384ecdc31b4" + }, + "racket": { + "revision": "dc9c33451fefc2d84d226e55c828adc8a66f2e37" + }, + "rasi": { + "revision": "5f04634dd4e12de4574c4a3dc9d6d5d4da4a2a1b" + }, + "regex": { + "revision": "e1cfca3c79896ff79842f057ea13e529b66af636" + }, + "rego": { + "revision": "b2667c975f07b33be3ceb83bea5cfbad88095866" + }, + "rnoweb": { + "revision": "502c1126dc6777f09af5bef16e72a42f75bd081e" + }, + "rst": { + "revision": "25e6328872ac3a764ba8b926aea12719741103f1" + }, + "ruby": { + "revision": "c91960320d0f337bdd48308a8ad5500bd2616979" + }, + "rust": { + "revision": "f7fb205c424b0962de59b26b931fe484e1262b35" + }, + "scala": { + "revision": "140c96cf398693189d4e50f76d19ddfcd8a018f8" + }, + "scheme": { + "revision": "16bdcf0495865e17ae5b995257458e31e8b7f450" + }, + "scss": { + "revision": "c478c6868648eff49eb04a4df90d703dc45b312a" + }, + "slint": { + "revision": "d422300f5d6ccce8f9a617dfed57aafb636fadb2" + }, + "solidity": { + "revision": "52ed0880c0126df2f2c7693f215fe6f38e4a2e0a" + }, + "sparql": { + "revision": "05f949d3c1c15e3261473a244d3ce87777374dec" + }, + "sql": { + "revision": "a4dd131eeb9fe7f3c9c2ca0f506f6d58d9986a97" + }, + "supercollider": { + "revision": "90c6d9f777d2b8c4ce497c48b5f270a44bcf3ea0" + }, + "surface": { + "revision": "f4586b35ac8548667a9aaa4eae44456c1f43d032" + }, + "svelte": { + "revision": "52e122ae68b316d3aa960a0a422d3645ba717f42" + }, + "swift": { + "revision": "693411cb5a1167311ccd84708348281630562726" + }, + "sxhkdrc": { + "revision": "440d5f913d9465c9c776a1bd92334d32febcf065" + }, + "teal": { + "revision": "1ae8c68e90523b26b93af56feb7868fe4214e2b2" + }, + "tiger": { + "revision": "a233ebe360a73a92c50978e5c4e9e471bc59ff42" + }, + "tlaplus": { + "revision": "27e6d238a5708b0490f43351f6e0baeaab4c9c1f" + }, + "todotxt": { + "revision": "0207f6a4ab6aeafc4b091914d31d8235049a2578" + }, + "toml": { + "revision": "8bd2056818b21860e3d756b5a58c4f6e05fb744e" + }, + "tsx": { + "revision": "faad9094f4061a43d4e9005439e9e85c6541ebe7" + }, + "turtle": { + "revision": "085437f5cb117703b7f520dd92161140a684f092" + }, + "twig": { + "revision": "2457993b13a06dec2706e6a6c3d5b65bb23024b8" + }, + "typescript": { + "revision": "faad9094f4061a43d4e9005439e9e85c6541ebe7" + }, + "v": { + "revision": "66b92a89ef1e149300df79c0b2a934ad959c8eec" + }, + "vala": { + "revision": "8f690bfa639f2b83d1fb938ed3dd98a7ba453e8b" + }, + "verilog": { + "revision": "4457145e795b363f072463e697dfe2f6973c9a52" + }, + "vhs": { + "revision": "8a0df32b72a8cf8d3e3e84f16c19e9ba46d3dba5" + }, + "vim": { + "revision": "55ff1b080c09edeced9b748cf4c16d0b49d17fb9" + }, + "vue": { + "revision": "91fe2754796cd8fba5f229505a23fa08f3546c06" + }, + "wgsl": { + "revision": "61d2604525d47238ecbce8aa38f10cb81ba68fd3" + }, + "yaml": { + "revision": "0e36bed171768908f331ff7dff9d956bae016efb" + }, + "yang": { + "revision": "2c0e6be8dd4dcb961c345fa35c309ad4f5bd3502" + }, + "zig": { + "revision": "d90d38d28ce8cc27bfea8b4e0c75211e9e2398ca" + } +} diff --git a/lua/nvim-treesitter.lua b/lua/nvim-treesitter.lua new file mode 100644 index 000000000..963fe7309 --- /dev/null +++ b/lua/nvim-treesitter.lua @@ -0,0 +1,22 @@ +local install = require "nvim-treesitter.install" +local utils = require "nvim-treesitter.utils" +local info = require "nvim-treesitter.info" +local configs = require "nvim-treesitter.configs" +local statusline = require "nvim-treesitter.statusline" + +-- Registers all query predicates +require "nvim-treesitter.query_predicates" + +local M = {} + +function M.setup() + utils.setup_commands("install", install.commands) + utils.setup_commands("info", info.commands) + utils.setup_commands("configs", configs.commands) + configs.init() +end + +M.define_modules = configs.define_modules +M.statusline = statusline.statusline + +return M diff --git a/lua/nvim-treesitter/_meta/parsers.lua b/lua/nvim-treesitter/_meta/parsers.lua deleted file mode 100644 index 3a97b35a5..000000000 --- a/lua/nvim-treesitter/_meta/parsers.lua +++ /dev/null @@ -1,47 +0,0 @@ ----@meta -error('Cannot require a meta file') - ----@class InstallInfo ---- ----URL of parser repo (Github) ----@field url string ---- ----Commit hash of parser to download (compatible with queries) ----@field revision string ---- ----Branch of parser repo to download (if not default branch) ----@field branch? string ---- ----Location of `grammar.js` in repo (if not at root, e.g., in a monorepo) ----@field location? string ---- ----Repo does not contain a `parser.c`; must be generated from grammar first ----@field generate? boolean ---- ----Generate parser from `grammar.json` instead of `grammar.js` (default true) ----@field generate_from_json? boolean ---- ----Parser repo is a local directory; overrides `url`, `revision`, and `branch` ----@field path? string ---- ----Directory with queries to be installed ----@field queries? string - ----@class ParserInfo ---- ----Information necessary to build and install the parser (empty for query-only language) ----@field install_info? InstallInfo ---- ----List of Github users maintaining the queries for Neovim ----@field maintainers? string[] ---- ----List of other languages to install (e.g., if queries inherit from them) ----@field requires? string[] ---- ----Language support tier, maps to "stable", "unstable", "unmaintained", "unsupported" ----@field tier integer ---- ----Explanatory footnote text to add in SUPPORTED_LANGUAGES.md ----@field readme_note? string - ----@alias nvim-ts.parsers table diff --git a/lua/nvim-treesitter/async.lua b/lua/nvim-treesitter/async.lua deleted file mode 100644 index a0a59e4b1..000000000 --- a/lua/nvim-treesitter/async.lua +++ /dev/null @@ -1,736 +0,0 @@ ----@meta nvim-treesitter.async vendored file, don't diagnose -local pcall = copcall or pcall - ---- @param ... any ---- @return {[integer]: any, n: integer} -local function pack_len(...) - return { n = select('#', ...), ... } -end - ---- like unpack() but use the length set by F.pack_len if present ---- @param t? { [integer]: any, n?: integer } ---- @param first? integer ---- @return ...any -local function unpack_len(t, first) - if t then - return unpack(t, first or 1, t.n or table.maxn(t)) - end -end - ---- @class async -local M = {} - ---- Weak table to keep track of running tasks ---- @type table -local threads = setmetatable({}, { __mode = 'k' }) - ---- @return async.Task? -local function running() - local task = threads[coroutine.running()] - if task and not (task:_completed() or task._closing) then - return task - end -end - ---- Base class for async tasks. Async functions should return a subclass of ---- this. This is designed specifically to be a base class of uv_handle_t ---- @class async.Handle ---- @field close fun(self: async.Handle, callback?: fun()) ---- @field is_closing? fun(self: async.Handle): boolean - ---- @alias async.CallbackFn fun(...: any): async.Handle? - ---- @class async.Task : async.Handle ---- @field package _callbacks table ---- @field package _callback_pos integer ---- @field private _thread thread ---- ---- Tasks can call other async functions (task of callback functions) ---- when we are waiting on a child, we store the handle to it here so we can ---- cancel it. ---- @field private _current_child? async.Handle ---- ---- Error result of the task is an error occurs. ---- Must use `await` to get the result. ---- @field private _err? any ---- ---- Result of the task. ---- Must use `await` to get the result. ---- @field private _result? any[] -local Task = {} -Task.__index = Task - ---- @private ---- @param func function ---- @return async.Task -function Task._new(func) - local thread = coroutine.create(func) - - local self = setmetatable({ - _closing = false, - _thread = thread, - _callbacks = {}, - _callback_pos = 1, - }, Task) - - threads[thread] = self - - return self -end - ---- @param callback fun(err?: any, ...: any) -function Task:await(callback) - if self._closing then - callback('closing') - elseif self:_completed() then -- TODO(lewis6991): test - -- Already finished or closed - callback(self._err, unpack_len(self._result)) - else - self._callbacks[self._callback_pos] = callback - self._callback_pos = self._callback_pos + 1 - end -end - ---- @package -function Task:_completed() - return (self._err or self._result) ~= nil -end - --- Use max 32-bit signed int value to avoid overflow on 32-bit systems. --- Do not use `math.huge` as it is not interpreted as a positive integer on all --- platforms. -local MAX_TIMEOUT = 2 ^ 31 - 1 - ---- Synchronously wait (protected) for a task to finish (blocking) ---- ---- If an error is returned, `Task:traceback()` can be used to get the ---- stack trace of the error. ---- ---- Example: ---- ```lua ---- ---- local ok, err_or_result = task:pwait(10) ---- ---- if not ok then ---- error(task:traceback(err_or_result)) ---- end ---- ---- local _, result = assert(task:pwait(10)) ---- ``` ---- ---- Can be called if a task is closing. ---- @param timeout? integer ---- @return boolean status ---- @return any ... result or error -function Task:pwait(timeout) - local done = vim.wait(timeout or MAX_TIMEOUT, function() - -- Note we use self:_completed() instead of self:await() to avoid creating a - -- callback. This avoids having to cleanup/unregister any callback in the - -- case of a timeout. - return self:_completed() - end) - - if not done then - return false, 'timeout' - elseif self._err then - return false, self._err - else - return true, unpack_len(self._result) - end -end - ---- Synchronously wait for a task to finish (blocking) ---- ---- Example: ---- ```lua ---- local result = task:wait(10) -- wait for 10ms or else error ---- ---- local result = task:wait() -- wait indefinitely ---- ``` ---- @param timeout? integer Timeout in milliseconds ---- @return any ... result -function Task:wait(timeout) - local res = pack_len(self:pwait(timeout)) - local stat = res[1] - - if not stat then - error(self:traceback(res[2])) - end - - return unpack_len(res, 2) -end - ---- @private ---- @param msg? string ---- @param _lvl? integer ---- @return string -function Task:_traceback(msg, _lvl) - _lvl = _lvl or 0 - - local thread = ('[%s] '):format(self._thread) - - local child = self._current_child - if getmetatable(child) == Task then - --- @cast child async.Task - msg = child:_traceback(msg, _lvl + 1) - end - - local tblvl = getmetatable(child) == Task and 2 or nil - msg = (msg or '') .. debug.traceback(self._thread, '', tblvl):gsub('\n\t', '\n\t' .. thread) - - if _lvl == 0 then - --- @type string - msg = msg - :gsub('\nstack traceback:\n', '\nSTACK TRACEBACK:\n', 1) - :gsub('\nstack traceback:\n', '\n') - :gsub('\nSTACK TRACEBACK:\n', '\nstack traceback:\n', 1) - end - - return msg -end - ---- Get the traceback of a task when it is not active. ---- Will also get the traceback of nested tasks. ---- ---- @param msg? string ---- @return string -function Task:traceback(msg) - return self:_traceback(msg) -end - ---- If a task completes with an error, raise the error -function Task:raise_on_error() - self:await(function(err) - if err then - error(self:_traceback(err), 0) - end - end) - return self -end - ---- @private ---- @param err? any ---- @param result? {[integer]: any, n: integer} -function Task:_finish(err, result) - self._current_child = nil - self._err = err - self._result = result - threads[self._thread] = nil - - local errs = {} --- @type string[] - for _, cb in pairs(self._callbacks) do - --- @type boolean, string - local ok, cb_err = pcall(cb, err, unpack_len(result)) - if not ok then - errs[#errs + 1] = cb_err - end - end - - if #errs > 0 then - error(table.concat(errs, '\n'), 0) - end -end - ---- @return boolean -function Task:is_closing() - return self._closing -end - ---- Close the task and all its children. ---- If callback is provided it will run asynchronously, ---- else it will run synchronously. ---- ---- @param callback? fun() -function Task:close(callback) - if self:_completed() then - if callback then - callback() - end - return - end - - if self._closing then - return - end - - self._closing = true - - if callback then -- async - if self._current_child then - self._current_child:close(function() - self:_finish('closed') - callback() - end) - else - self:_finish('closed') - callback() - end - else -- sync - if self._current_child then - self._current_child:close(function() - self:_finish('closed') - end) - else - self:_finish('closed') - end - vim.wait(0, function() - return self:_completed() - end) - end -end - ---- @param obj any ---- @return boolean -local function is_async_handle(obj) - local ty = type(obj) - return (ty == 'table' or ty == 'userdata') and vim.is_callable(obj.close) -end - ---- @param ... any -function Task:_resume(...) - --- @type [boolean, string|async.CallbackFn] - local ret = pack_len(coroutine.resume(self._thread, ...)) - local stat = ret[1] - - if not stat then - -- Coroutine had error - self:_finish(ret[2]) - elseif coroutine.status(self._thread) == 'dead' then - -- Coroutine finished - local result = pack_len(unpack_len(ret, 2)) - self:_finish(nil, result) - else - local fn = ret[2] - --- @cast fn -string - - -- TODO(lewis6991): refine error handler to be more specific - local ok, r - ok, r = pcall(fn, function(...) - if is_async_handle(r) then - --- @cast r async.Handle - -- We must close children before we resume to ensure - -- all resources are collected. - local args = pack_len(...) - r:close(function() - self:_resume(unpack_len(args)) - end) - else - self:_resume(...) - end - end) - - if not ok then - self:_finish(r) - elseif is_async_handle(r) then - self._current_child = r - end - end -end - ---- @return 'running'|'suspended'|'normal'|'dead'? -function Task:status() - return coroutine.status(self._thread) -end - ---- Run a function in an async context, asynchronously. ---- ---- Examples: ---- ```lua ---- -- The two below blocks are equivalent: ---- ---- -- Run a uv function and wait for it ---- local stat = async.arun(function() ---- return async.await(2, vim.uv.fs_stat, 'foo.txt') ---- end):wait() ---- ---- -- Since uv functions have sync versions. You can just do: ---- local stat = vim.fs_stat('foo.txt') ---- ``` ---- @generic T, R ---- @param func async fun(...: T...): R... ---- @param ... T... ---- @return async.Task -function M.arun(func, ...) - local task = Task._new(func) - task:_resume(...) - return task -end - ---- @alias async.TaskFun fun(...: T...): async.Task - ---- @generic T, R ---- @class async._TaskFun ---- @field package _fun async fun(...: T...): R... ---- @operator call(...: T...): async.Task -local TaskFun = {} -TaskFun.__index = TaskFun - ---- @generic T, R ---- @param self async._TaskFun ---- @param ... T... ---- @return async.Task -function TaskFun:__call(...) - return M.arun(self._fun, ...) -end - ---- Create an async function ---- @generic T, R ---- @param fun async fun(...: T...): R... ---- @return async.TaskFun -function M.async(fun) - return setmetatable({ _fun = fun }, TaskFun) -end - ---- Returns the status of a task’s thread. ---- ---- @param task? async.Task ---- @return 'running'|'suspended'|'normal'|'dead'? -function M.status(task) - task = task or running() - if task then - assert(getmetatable(task) == Task, 'Expected Task') - return task:status() - end -end - ---- @async ---- @generic R1, R2, R3, R4 ---- @param fun fun(callback: fun(r1: R1, r2: R2, r3: R3, r4: R4)): any? ---- @return R1, R2, R3, R4 -local function yield(fun) - assert(type(fun) == 'function', 'Expected function') - return coroutine.yield(fun) -end - ---- @async ---- @param task async.Task ---- @return any ... -local function await_task(task) - --- @param callback fun(err?: string, ...: any) - --- @return function - local res = pack_len(yield(function(callback) - task:await(callback) - return task - end)) - - local err = res[1] - - if err then - -- TODO(lewis6991): what is the correct level to pass? - error(err, 0) - end - - return unpack_len(res, 2) -end - ---- Asynchronous blocking wait ---- @param argc integer ---- @param fun async.CallbackFn ---- @param ... any func arguments ---- @return any ... -local function await_cbfun(argc, fun, ...) - local args = pack_len(...) - - --- @param callback fun(...:any) - --- @return any? - return yield(function(callback) - args[argc] = callback - args.n = math.max(args.n, argc) - return fun(unpack_len(args)) - end) -end - ---- @generic T, R ---- @param taskfun async.TaskFun ---- @param ... T... ---- @return R... -local function await_taskfun(taskfun, ...) - return taskfun._fun(...) -end - ---- Asynchronous blocking wait ---- ---- Example: ---- ```lua ---- local task = async.arun(function() ---- return 1, 'a' ---- end) ---- ---- local task_fun = async.async(function(arg) ---- return 2, 'b', arg ---- end) ---- ---- async.arun(function() ---- do -- await a callback function ---- async.await(1, vim.schedule) ---- end ---- ---- do -- await a task (new async context) ---- local n, s = async.await(task) ---- assert(n == 1 and s == 'a') ---- end ---- ---- do -- await a started task function (new async context) ---- local n, s, arg = async.await(task_fun('A')) ---- assert(n == 2) ---- assert(s == 'b') ---- assert(args == 'A') ---- end ---- ---- do -- await a task function (re-using the current async context) ---- local n, s, arg = async.await(task_fun, 'B') ---- assert(n == 2) ---- assert(s == 'b') ---- assert(args == 'B') ---- end ---- end) ---- ``` ---- @async ---- @overload fun(argc: integer, func: async.CallbackFn, ...:any): any ... ---- @overload fun(task: async.Task): any ... ---- @overload fun(taskfun: async.TaskFun): any ... -function M.await(...) - assert(running(), 'Not in async context') - - local arg1 = select(1, ...) - - if type(arg1) == 'number' then - return await_cbfun(...) - elseif getmetatable(arg1) == Task then - return await_task(...) - elseif getmetatable(arg1) == TaskFun then - return await_taskfun(...) - end - - error('Invalid arguments, expected Task or (argc, func) got: ' .. type(arg1), 2) -end - ---- Creates an async function with a callback style function. ---- ---- Example: ---- ---- ```lua ---- --- Note the callback argument is not present in the return function ---- --- @type fun(timeout: integer) ---- local sleep = async.awrap(2, function(timeout, callback) ---- local timer = vim.uv.new_timer() ---- timer:start(timeout * 1000, 0, callback) ---- -- uv_timer_t provides a close method so timer will be ---- -- cleaned up when this function finishes ---- return timer ---- end) ---- ---- async.arun(function() ---- print('hello') ---- sleep(2) ---- print('world') ---- end) ---- ``` ---- ---- local atimer = async.awrap( ---- @param argc integer ---- @param func async.CallbackFn ---- @return async function -function M.awrap(argc, func) - assert(type(argc) == 'number') - assert(type(func) == 'function') - --- @async - return function(...) - return M.await(argc, func, ...) - end -end - -if vim.schedule then - --- An async function that when called will yield to the Neovim scheduler to be - --- able to call the API. - M.schedule = M.awrap(1, vim.schedule) -end - ---- Create a function that runs a function when it is garbage collected. ---- @generic F ---- @param f F ---- @param gc fun() ---- @return F -local function gc_fun(f, gc) - local proxy = newproxy(true) - local proxy_mt = getmetatable(proxy) - proxy_mt.__gc = gc - proxy_mt.__call = function(_, ...) - return f(...) - end - - return proxy -end - ---- @param task_cbs table -local function gc_cbs(task_cbs) - for task, tcb in pairs(task_cbs) do - for j, cb in pairs(task._callbacks) do - if cb == tcb then - task._callbacks[j] = nil - break - end - end - end -end - ---- @async ---- Example: ---- ```lua ---- local task1 = async.arun(function() ---- return 1, 'a' ---- end) ---- ---- local task2 = async.arun(function() ---- return 1, 'a' ---- end) ---- ---- local task3 = async.arun(function() ---- error('task3 error') ---- end) ---- ---- async.arun(function() ---- for i, err, r1, r2 in async.iter({task1, task2, task3}) ---- print(i, err, r1, r2) ---- end ---- end) ---- ``` ---- ---- Prints: ---- ``` ---- 1 nil 1 'a' ---- 2 nil 2 'b' ---- 3 'task3 error' nil nil ---- ``` ---- ---- @param tasks async.Task[] ---- @return fun(): (integer?, any?, ...) -function M.iter(tasks) - assert(running(), 'Not in async context') - - local results = {} --- @type [integer, any, ...][] - - -- Iter blocks in an async context so only one waiter is needed - local waiter = nil - local task_cbs = {} --- @type table - local remaining = #tasks - - --- If can_gc_cbs is true, then the iterator function has been garbage - --- collected and means any awaiters can also be garbage collected. The - --- only time we can't do this is if with the special case when iter() is - --- called anonymously (`local i = async.iter(tasks)()`), so we should not - --- garbage collect the callbacks until at least one awaiter is called. - local can_gc_cbs = false - - for i, task in ipairs(tasks) do - local function cb(err, ...) - if can_gc_cbs == true then - gc_cbs(task_cbs) - end - - local callback = waiter - - -- Clear waiter before calling it - waiter = nil - - remaining = remaining - 1 - if callback then - -- Iterator is waiting, yield to it - callback(i, err, ...) - else - -- Task finished before Iterator was called. Store results. - table.insert(results, pack_len(i, err, ...)) - end - end - - task_cbs[task] = cb - task:await(cb) - end - - return gc_fun( - M.awrap(1, function(callback) - if next(results) then - local res = table.remove(results, 1) - callback(unpack_len(res)) - elseif remaining == 0 then - callback() -- finish - else - assert(not waiter, 'internal error: waiter already set') - waiter = callback - end - end), - function() - -- Don't gc callbacks just yet. Wait until at least one of them is called. - can_gc_cbs = true - end - ) -end - -do -- join() - --- @param results table - --- @param i integer - --- @param ... any - --- @return boolean - local function collect(results, i, ...) - if i then - results[i] = pack_len(...) - end - return i ~= nil - end - - --- @param iter fun(): ... - --- @return table - local function drain_iter(iter) - local results = {} --- @type table - while collect(results, iter()) do - end - return results - end - - --- @async - --- Wait for all tasks to finish and return their results. - --- - --- Example: - --- ```lua - --- local task1 = async.arun(function() - --- return 1, 'a' - --- end) - --- - --- local task2 = async.arun(function() - --- return 1, 'a' - --- end) - --- - --- local task3 = async.arun(function() - --- error('task3 error') - --- end) - --- - --- async.arun(function() - --- local results = async.join({task1, task2, task3}) - --- print(vim.inspect(results)) - --- end) - --- ``` - --- - --- Prints: - --- ``` - --- { - --- [1] = { nil, 1, 'a' }, - --- [2] = { nil, 2, 'b' }, - --- [3] = { 'task2 error' }, - --- } - --- ``` - --- @param tasks async.Task[] - --- @return table - function M.join(tasks) - assert(running(), 'Not in async context') - return drain_iter(M.iter(tasks)) - end - - --- @async - --- @param tasks async.Task[] - --- @return integer?, any?, ...? - function M.joinany(tasks) - return M.iter(tasks)() - end -end - -return M diff --git a/lua/nvim-treesitter/caching.lua b/lua/nvim-treesitter/caching.lua new file mode 100644 index 000000000..cff0b5a1f --- /dev/null +++ b/lua/nvim-treesitter/caching.lua @@ -0,0 +1,48 @@ +local api = vim.api + +local M = {} + +--- Creates a cache table for buffers keyed by a type name. +--- Cache entries attach to the buffer and cleanup entries +--- as buffers are detached. +function M.create_buffer_cache() + local cache = {} + + local items = setmetatable({}, { + __index = function(tbl, key) + rawset(tbl, key, {}) + return rawget(tbl, key) + end, + }) + + function cache.set(type_name, bufnr, value) + if not cache.has(type_name, bufnr) then + -- Clean up the cache if the buffer is detached + -- to avoid memory leaks + api.nvim_buf_attach(bufnr, false, { + on_detach = function() + cache.remove(type_name, bufnr) + return true + end, + }) + end + + items[type_name][bufnr] = value + end + + function cache.get(type_name, bufnr) + return items[type_name][bufnr] + end + + function cache.has(type_name, bufnr) + return cache.get(type_name, bufnr) ~= nil + end + + function cache.remove(type_name, bufnr) + items[type_name][bufnr] = nil + end + + return cache +end + +return M diff --git a/lua/nvim-treesitter/config.lua b/lua/nvim-treesitter/config.lua deleted file mode 100644 index 3ea96f36d..000000000 --- a/lua/nvim-treesitter/config.lua +++ /dev/null @@ -1,174 +0,0 @@ -local M = {} - -M.tiers = { 'stable', 'unstable', 'unmaintained', 'unsupported' } - ----@class TSConfig ----@field install_dir string - ----@type TSConfig -local config = { - install_dir = vim.fs.joinpath(vim.fn.stdpath('data') --[[@as string]], 'site'), -} - ----Setup call for users to override configuration configurations. ----@param user_data TSConfig? user configuration table -function M.setup(user_data) - if user_data then - if user_data.install_dir then - user_data.install_dir = vim.fs.normalize(user_data.install_dir) - vim.o.rtp = user_data.install_dir .. ',' .. vim.o.rtp - end - config = vim.tbl_deep_extend('force', config, user_data) - end -end - --- Returns the install path for parsers, parser info, and queries. --- If the specified directory does not exist, it is created. ----@param dir_name string ----@return string -function M.get_install_dir(dir_name) - local dir = vim.fs.joinpath(config.install_dir, dir_name) - - if not vim.uv.fs_stat(dir) then - local ok, err = pcall(vim.fn.mkdir, dir, 'p', '0755') - if not ok then - local log = require('nvim-treesitter.log') - log.error(err --[[@as string]]) - end - end - return dir -end - ----@param type 'queries'|'parsers'? ----@return string[] -function M.get_installed(type) - local installed = {} --- @type table - if not (type and type == 'parsers') then - for f in vim.fs.dir(M.get_install_dir('queries')) do - installed[f] = true - end - end - if not (type and type == 'queries') then - for f in vim.fs.dir(M.get_install_dir('parser')) do - installed[vim.fn.fnamemodify(f, ':r')] = true - end - end - return vim.tbl_keys(installed) -end - --- Get a list of all available parsers ----@param tier integer? only get parsers of specified tier ----@return string[] -function M.get_available(tier) - vim.api.nvim_exec_autocmds('User', { pattern = 'TSUpdate' }) - local parsers = require('nvim-treesitter.parsers') - --- @type string[] - local languages = vim.tbl_keys(parsers) - table.sort(languages) - if tier then - languages = vim.tbl_filter( - --- @param p string - function(p) - return parsers[p] ~= nil and parsers[p].tier == tier - end, - languages - ) - end - return languages -end - -local function expand_tiers(list) - for i, tier in ipairs(M.tiers) do - if vim.list_contains(list, tier) then - list = vim.tbl_filter( - --- @param l string - function(l) - return l ~= tier - end, - list - ) - vim.list_extend(list, M.get_available(i)) - end - end - - return list -end - ----Normalize languages ----@param languages? string[]|string ----@param skip? { missing: boolean?, unsupported: boolean?, installed: boolean?, dependencies: boolean? } ----@return string[] -function M.norm_languages(languages, skip) - if not languages then - return {} - elseif type(languages) == 'string' then - languages = { languages } - end - - if vim.list_contains(languages, 'all') then - if skip and skip.missing then - return M.get_installed() - end - languages = M.get_available() - end - - languages = expand_tiers(languages) - - if skip and skip.installed then - local installed = M.get_installed() - languages = vim.tbl_filter( - --- @param v string - function(v) - return not vim.list_contains(installed, v) - end, - languages - ) - end - - if skip and skip.missing then - local installed = M.get_installed() - languages = vim.tbl_filter( - --- @param v string - function(v) - return vim.list_contains(installed, v) - end, - languages - ) - end - - local parsers = require('nvim-treesitter.parsers') - languages = vim.tbl_filter( - --- @param v string - function(v) - if parsers[v] ~= nil then - return true - else - require('nvim-treesitter.log').warn('skipping unsupported language: ' .. v) - return false - end - end, - languages - ) - - if skip and skip.unsupported then - languages = vim.tbl_filter( - --- @param v string - function(v) - return not (parsers[v] and parsers[v].tier and parsers[v].tier == 4) - end, - languages - ) - end - - if not (skip and skip.dependencies) then - for _, lang in pairs(languages) do - if parsers[lang] and parsers[lang].requires then - vim.list_extend(languages, parsers[lang].requires) - end - end - end - - return vim.list.unique(languages) -end - -return M diff --git a/lua/nvim-treesitter/configs.lua b/lua/nvim-treesitter/configs.lua new file mode 100644 index 000000000..cad4bb788 --- /dev/null +++ b/lua/nvim-treesitter/configs.lua @@ -0,0 +1,617 @@ +local api = vim.api + +local queries = require "nvim-treesitter.query" +local ts_query = require "vim.treesitter.query" +local parsers = require "nvim-treesitter.parsers" +local utils = require "nvim-treesitter.utils" +local caching = require "nvim-treesitter.caching" + +local M = {} + +---@class TSConfig +---@field modules {[string]:TSModule} +---@field sync_install boolean +---@field ensure_installed string[]|string +---@field ignore_install string[] +---@field auto_install boolean +---@field update_strategy string +---@field parser_install_dir string|nil + +---@type TSConfig +local config = { + modules = {}, + sync_install = false, + ensure_installed = {}, + auto_install = false, + ignore_install = {}, + update_strategy = "lockfile", + parser_install_dir = nil, +} +-- List of modules that need to be setup on initialization. +local queued_modules_defs = {} +-- Whether we've initialized the plugin yet. +local is_initialized = false + +---@class TSModule +---@field module_path string +---@field enable boolean|string[]|function(string): boolean +---@field disable boolean|string[]|function(string): boolean +---@field is_supported function(string): boolean +---@field attach function(string) +---@field detach function(string) +---@field enabled_buffers table + +---@type {[string]: TSModule} +local builtin_modules = { + highlight = { + module_path = "nvim-treesitter.highlight", + -- @deprecated: use `highlight.set_custom_captures` instead + custom_captures = {}, + enable = false, + is_supported = function(lang) + return queries.has_highlights(lang) + end, + additional_vim_regex_highlighting = false, + }, + incremental_selection = { + module_path = "nvim-treesitter.incremental_selection", + enable = false, + keymaps = { + init_selection = "gnn", + node_incremental = "grn", + scope_incremental = "grc", + node_decremental = "grm", + }, + is_supported = function() + return true + end, + }, + indent = { + module_path = "nvim-treesitter.indent", + enable = false, + is_supported = queries.has_indents, + }, +} + +local attached_buffers_by_module = caching.create_buffer_cache() + +---Resolves a module by requiring the `module_path` or using the module definition. +---@param mod_name string +---@return TSModule|nil +local function resolve_module(mod_name) + local config_mod = M.get_module(mod_name) + + if not config_mod then + return + end + + if type(config_mod.attach) == "function" and type(config_mod.detach) == "function" then + return config_mod + elseif type(config_mod.module_path) == "string" then + return require(config_mod.module_path) + end +end + +---Enables and attaches the module to a buffer for lang. +---@param mod string path to module +---@param bufnr integer|nil buffer number, defaults to current buffer +---@param lang string|nil language, defaults to current language +local function enable_module(mod, bufnr, lang) + local module = M.get_module(mod) + if not module then + return + end + + bufnr = bufnr or api.nvim_get_current_buf() + lang = lang or parsers.get_buf_lang(bufnr) + + if not module.enable then + if module.enabled_buffers then + module.enabled_buffers[bufnr] = true + else + module.enabled_buffers = { [bufnr] = true } + end + end + + M.attach_module(mod, bufnr, lang) +end + +---Enables autocomands for the module. +---After the module is loaded `loaded` will be set to true for the module. +---@param mod string path to module +local function enable_mod_conf_autocmd(mod) + local config_mod = M.get_module(mod) + if not config_mod or config_mod.loaded then + return + end + + api.nvim_create_autocmd("FileType", { + group = api.nvim_create_augroup("NvimTreesitter-" .. mod, {}), + callback = function(args) + require("nvim-treesitter.configs").reattach_module(mod, args.buf) + end, + desc = "Reattach module", + }) + + config_mod.loaded = true +end + +---Enables the module globally and for all current buffers. +---After enabled, `enable` will be set to true for the module. +---@param mod string path to module +local function enable_all(mod) + local config_mod = M.get_module(mod) + if not config_mod then + return + end + + enable_mod_conf_autocmd(mod) + config_mod.enable = true + config_mod.enabled_buffers = nil + + for _, bufnr in pairs(api.nvim_list_bufs()) do + enable_module(mod, bufnr) + end +end + +---Disables and detaches the module for a buffer. +---@param mod string path to module +---@param bufnr integer buffer number, defaults to current buffer +local function disable_module(mod, bufnr) + local module = M.get_module(mod) + if not module then + return + end + + bufnr = bufnr or api.nvim_get_current_buf() + if module.enabled_buffers then + module.enabled_buffers[bufnr] = false + end + M.detach_module(mod, bufnr) +end + +---Disables autocomands for the module. +---After the module is unloaded `loaded` will be set to false for the module. +---@param mod string path to module +local function disable_mod_conf_autocmd(mod) + local config_mod = M.get_module(mod) + if not config_mod or not config_mod.loaded then + return + end + api.nvim_clear_autocmds { event = "FileType", group = "NvimTreesitter-" .. mod } + config_mod.loaded = false +end + +---Disables the module globally and for all current buffers. +---After disabled, `enable` will be set to false for the module. +---@param mod string path to module +local function disable_all(mod) + local config_mod = M.get_module(mod) + if not config_mod then + return + end + + config_mod.enabled_buffers = nil + disable_mod_conf_autocmd(mod) + config_mod.enable = false + + for _, bufnr in pairs(api.nvim_list_bufs()) do + disable_module(mod, bufnr) + end +end + +---Toggles a module for a buffer +---@param mod string path to module +---@param bufnr integer buffer number, defaults to current buffer +---@param lang string language, defaults to current language +local function toggle_module(mod, bufnr, lang) + bufnr = bufnr or api.nvim_get_current_buf() + lang = lang or parsers.get_buf_lang(bufnr) + + if attached_buffers_by_module.has(mod, bufnr) then + disable_module(mod, bufnr) + else + enable_module(mod, bufnr, lang) + end +end + +-- Toggles the module globally and for all current buffers. +-- @param mod path to module +local function toggle_all(mod) + local config_mod = M.get_module(mod) + if not config_mod then + return + end + + if config_mod.enable then + disable_all(mod) + else + enable_all(mod) + end +end + +---Recurses through all modules including submodules +---@param accumulator function called for each module +---@param root {[string]: TSModule} root configuration table to start at +---@param path string|nil prefix path +local function recurse_modules(accumulator, root, path) + root = root or config.modules + + for name, module in pairs(root) do + local new_path = path and (path .. "." .. name) or name + + if M.is_module(module) then + accumulator(name, module, new_path, root) + elseif type(module) == "table" then + recurse_modules(accumulator, module, new_path) + end + end +end + +---Shows current configuration of all nvim-treesitter modules +---@param process_function function used as the `process` parameter +--- for vim.inspect (https://github.com/kikito/inspect.lua#optionsprocess) +local function config_info(process_function) + process_function = process_function + or function(item, path) + if path[#path] == vim.inspect.METATABLE then + return + end + if path[#path] == "is_supported" then + return + end + return item + end + print(vim.inspect(config, { process = process_function })) +end + +---@param query_group string +---@param lang string +function M.edit_query_file(query_group, lang) + lang = lang or parsers.get_buf_lang() + local files = ts_query.get_query_files(lang, query_group, true) + if #files == 0 then + utils.notify "No query file found! Creating a new one!" + M.edit_query_file_user_after(query_group, lang) + elseif #files == 1 then + vim.cmd(":edit " .. files[1]) + else + vim.ui.select(files, { prompt = "Select a file:" }, function(file) + if file then + vim.cmd(":edit " .. file) + end + end) + end +end + +---@param query_group string +---@param lang string +function M.edit_query_file_user_after(query_group, lang) + lang = lang or parsers.get_buf_lang() + local folder = utils.join_path(vim.fn.stdpath "config", "after", "queries", lang) + local file = utils.join_path(folder, query_group .. ".scm") + if vim.fn.isdirectory(folder) ~= 1 then + vim.ui.select({ "Yes", "No" }, { prompt = '"' .. folder .. '" does not exist. Create it?' }, function(choice) + if choice == "Yes" then + vim.fn.mkdir(folder, "p", "0755") + vim.cmd(":edit " .. file) + end + end) + else + vim.cmd(":edit " .. file) + end +end + +M.commands = { + TSBufEnable = { + run = enable_module, + args = { + "-nargs=1", + "-complete=custom,nvim_treesitter#available_modules", + }, + }, + TSBufDisable = { + run = disable_module, + args = { + "-nargs=1", + "-complete=custom,nvim_treesitter#available_modules", + }, + }, + TSBufToggle = { + run = toggle_module, + args = { + "-nargs=1", + "-complete=custom,nvim_treesitter#available_modules", + }, + }, + TSEnable = { + run = enable_all, + args = { + "-nargs=+", + "-complete=custom,nvim_treesitter#available_modules", + }, + }, + TSDisable = { + run = disable_all, + args = { + "-nargs=+", + "-complete=custom,nvim_treesitter#available_modules", + }, + }, + TSToggle = { + run = toggle_all, + args = { + "-nargs=+", + "-complete=custom,nvim_treesitter#available_modules", + }, + }, + TSConfigInfo = { + run = config_info, + args = { + "-nargs=0", + }, + }, + TSEditQuery = { + run = M.edit_query_file, + args = { + "-nargs=+", + "-complete=custom,nvim_treesitter#available_query_groups", + }, + }, + TSEditQueryUserAfter = { + run = M.edit_query_file_user_after, + args = { + "-nargs=+", + "-complete=custom,nvim_treesitter#available_query_groups", + }, + }, +} + +---@param mod string module +---@param lang string the language of the buffer +---@param bufnr integer the bufnr +function M.is_enabled(mod, lang, bufnr) + if not parsers.has_parser(lang) then + return false + end + + local module_config = M.get_module(mod) + if not module_config then + return false + end + + local buffer_enabled = module_config.enabled_buffers and module_config.enabled_buffers[bufnr] + local config_enabled = module_config.enable or buffer_enabled + if not config_enabled or not module_config.is_supported(lang) then + return false + end + + local disable = module_config.disable + if type(disable) == "function" then + if disable(lang, bufnr) then + return false + end + elseif type(disable) == "table" then + -- Otherwise it's a list of languages + for _, parser in pairs(disable) do + if lang == parser then + return false + end + end + end + + return true +end + +---Setup call for users to override module configurations. +---@param user_data TSConfig module overrides +function M.setup(user_data) + config.modules = vim.tbl_deep_extend("force", config.modules, user_data) + config.ignore_install = user_data.ignore_install or {} + config.parser_install_dir = user_data.parser_install_dir or nil + if config.parser_install_dir then + config.parser_install_dir = vim.fn.expand(config.parser_install_dir, ":p") + end + + config.auto_install = user_data.auto_install or false + if config.auto_install then + require("nvim-treesitter.install").setup_auto_install() + end + + local ensure_installed = user_data.ensure_installed or {} + if #ensure_installed > 0 then + if user_data.sync_install then + require("nvim-treesitter.install").ensure_installed_sync(ensure_installed) + else + require("nvim-treesitter.install").ensure_installed(ensure_installed) + end + end + + config.modules.ensure_installed = nil + config.ensure_installed = ensure_installed + + recurse_modules(function(_, _, new_path) + local data = utils.get_at_path(config.modules, new_path) + if data.enable then + enable_all(new_path) + end + end, config.modules) +end + +---Defines a table of modules that can be attached/detached to buffers +---based on language support. A module consist of the following properties: +---* @enable Whether the modules is enabled. Can be true or false. +---* @disable A list of languages to disable the module for. Only relevant if enable is true. +---* @keymaps A list of user mappings for a given module if relevant. +---* @is_supported A function which, given a ft, will return true if the ft works on the module. +---* @module_path A string path to a module file using `require`. The exported module must contain +--- an `attach` and `detach` function. This path is not required if `attach` and `detach` +--- functions are provided directly on the module definition. +---* @attach An attach function that is called for each buffer that the module is enabled for. This is required +--- if a `module_path` is not specified. +---* @detach A detach function that is called for each buffer that the module is enabled for. This is required +--- if a `module_path` is not specified. +---Modules are not setup until `init` is invoked by the plugin. This allows modules to be defined in any order +---and can be loaded lazily. +---@example +---require"nvim-treesitter".define_modules { +--- my_cool_module = { +--- attach = function() +--- do_some_cool_setup() +--- end, +--- detach = function() +--- do_some_cool_teardown() +--- end +--- } +---} +---@param mod_defs TSModule[] +function M.define_modules(mod_defs) + if not is_initialized then + table.insert(queued_modules_defs, mod_defs) + return + end + + recurse_modules(function(key, mod, _, group) + group[key] = vim.tbl_extend("keep", mod, { + enable = false, + disable = {}, + is_supported = function() + return true + end, + }) + end, mod_defs) + + config.modules = vim.tbl_deep_extend("keep", config.modules, mod_defs) + + for _, mod in ipairs(M.available_modules(mod_defs)) do + local module_config = M.get_module(mod) + if module_config and module_config.enable then + enable_mod_conf_autocmd(mod) + end + end +end + +---Attaches a module to a buffer +---@param mod_name string the module name +---@param bufnr integer the bufnr +---@param lang string the language of the buffer +function M.attach_module(mod_name, bufnr, lang) + bufnr = bufnr or api.nvim_get_current_buf() + lang = lang or parsers.get_buf_lang(bufnr) + local resolved_mod = resolve_module(mod_name) + + if resolved_mod and not attached_buffers_by_module.has(mod_name, bufnr) and M.is_enabled(mod_name, lang, bufnr) then + attached_buffers_by_module.set(mod_name, bufnr, true) + resolved_mod.attach(bufnr, lang) + end +end + +---Detaches a module to a buffer +---@param mod_name string the module name +---@param bufnr integer the bufnr +function M.detach_module(mod_name, bufnr) + local resolved_mod = resolve_module(mod_name) + bufnr = bufnr or api.nvim_get_current_buf() + + if resolved_mod and attached_buffers_by_module.has(mod_name, bufnr) then + attached_buffers_by_module.remove(mod_name, bufnr) + resolved_mod.detach(bufnr) + end +end + +---Same as attach_module, but if the module is already attached, detach it first. +---@param mod_name string the module name +---@param bufnr integer the bufnr +---@param lang string the language of the buffer +function M.reattach_module(mod_name, bufnr, lang) + M.detach_module(mod_name, bufnr) + M.attach_module(mod_name, bufnr, lang) +end + +---Gets available modules +---@param root {[string]:TSModule} table to find modules +function M.available_modules(root) + local modules = {} + + recurse_modules(function(_, _, path) + table.insert(modules, path) + end, root) + + return modules +end + +---Gets a module config by path +---@param mod_path string path to the module +---@return TSModule|nil the module or nil +function M.get_module(mod_path) + local mod = utils.get_at_path(config.modules, mod_path) + + return M.is_module(mod) and mod or nil +end + +---Determines whether the provided table is a module. +---A module should contain an attach and detach function. +---@param mod table the module table +---@return boolean +function M.is_module(mod) + return type(mod) == "table" + and ((type(mod.attach) == "function" and type(mod.detach) == "function") or type(mod.module_path) == "string") +end + +---Initializes built-in modules and any queued modules +---registered by plugins or the user. +function M.init() + is_initialized = true + M.define_modules(builtin_modules) + + for _, mod_def in ipairs(queued_modules_defs) do + M.define_modules(mod_def) + end +end + +---If parser_install_dir is not nil is used or created. +---If parser_install_dir is nil try the package dir of the nvim-treesitter +---plugin first, followed by the "site" dir from "runtimepath". "site" dir will +---be created if it doesn't exist. Using only the package dir won't work when +---the plugin is installed with Nix, since the "/nix/store" is read-only. +---@param folder_name string|nil +---@return string|nil, string|nil +function M.get_parser_install_dir(folder_name) + folder_name = folder_name or "parser" + + local install_dir + if config.parser_install_dir then + install_dir = config.parser_install_dir + else + install_dir = utils.get_package_path() + end + local parser_dir = utils.join_path(install_dir, folder_name) + + return utils.create_or_reuse_writable_dir( + parser_dir, + utils.join_space("Could not create parser dir '", parser_dir, "': "), + utils.join_space( + "Parser dir '", + parser_dir, + "' should be read/write (see README on how to configure an alternative install location)" + ) + ) +end + +function M.get_parser_info_dir() + return M.get_parser_install_dir "parser-info" +end + +function M.get_update_strategy() + return config.update_strategy +end + +function M.get_ignored_parser_installs() + return config.ignore_install or {} +end + +function M.get_ensure_installed_parsers() + return config.ensure_installed or {} +end + +return M diff --git a/lua/nvim-treesitter/fold.lua b/lua/nvim-treesitter/fold.lua new file mode 100644 index 000000000..50272622f --- /dev/null +++ b/lua/nvim-treesitter/fold.lua @@ -0,0 +1,119 @@ +local api = vim.api +local tsutils = require "nvim-treesitter.ts_utils" +local query = require "nvim-treesitter.query" +local parsers = require "nvim-treesitter.parsers" + +local M = {} + +-- This is cached on buf tick to avoid computing that multiple times +-- Especially not for every line in the file when `zx` is hit +local folds_levels = tsutils.memoize_by_buf_tick(function(bufnr) + local max_fold_level = api.nvim_win_get_option(0, "foldnestmax") + local trim_level = function(level) + if level > max_fold_level then + return max_fold_level + end + return level + end + + local parser = parsers.get_parser(bufnr) + + if not parser then + return {} + end + + local matches = query.get_capture_matches_recursively(bufnr, function(lang) + if query.has_folds(lang) then + return "@fold", "folds" + elseif query.has_locals(lang) then + return "@scope", "locals" + end + end) + + -- start..stop is an inclusive range + local start_counts = {} + local stop_counts = {} + + local prev_start = -1 + local prev_stop = -1 + + local min_fold_lines = api.nvim_win_get_option(0, "foldminlines") + + for _, match in ipairs(matches) do + local start, stop, stop_col + if match.metadata and match.metadata.range then + start, _, stop, stop_col = unpack(match.metadata.range) + else + start, _, stop, stop_col = match.node:range() + end + + if stop_col == 0 then + stop = stop - 1 + end + + local fold_length = stop - start + 1 + local should_fold = fold_length > min_fold_lines + + -- Fold only multiline nodes that are not exactly the same as previously met folds + -- Checking against just the previously found fold is sufficient if nodes + -- are returned in preorder or postorder when traversing tree + if should_fold and not (start == prev_start and stop == prev_stop) then + start_counts[start] = (start_counts[start] or 0) + 1 + stop_counts[stop] = (stop_counts[stop] or 0) + 1 + prev_start = start + prev_stop = stop + end + end + + local levels = {} + local current_level = 0 + + -- We now have the list of fold opening and closing, fill the gaps and mark where fold start + for lnum = 0, api.nvim_buf_line_count(bufnr) do + local prefix = "" + + local last_trimmed_level = trim_level(current_level) + current_level = current_level + (start_counts[lnum] or 0) + local trimmed_level = trim_level(current_level) + current_level = current_level - (stop_counts[lnum] or 0) + local next_trimmed_level = trim_level(current_level) + + -- Determine if it's the start/end of a fold + -- NB: vim's fold-expr interface does not have a mechanism to indicate that + -- two (or more) folds start at this line, so it cannot distinguish between + -- ( \n ( \n )) \n (( \n ) \n ) + -- versus + -- ( \n ( \n ) \n ( \n ) \n ) + -- If it did have such a mechanism, (trimmed_level - last_trimmed_level) + -- would be the correct number of starts to pass on. + if trimmed_level - last_trimmed_level > 0 then + prefix = ">" + elseif trimmed_level - next_trimmed_level > 0 then + -- Ending marks tend to confuse vim more than it helps, particularly when + -- the fold level changes by at least 2; we can uncomment this if + -- vim's behavior gets fixed. + -- prefix = "<" + prefix = "" + end + + levels[lnum + 1] = prefix .. tostring(trimmed_level) + end + + return levels +end) + +---@param lnum integer +---@return string +function M.get_fold_indic(lnum) + if not parsers.has_parser() or not lnum then + return "0" + end + + local buf = api.nvim_get_current_buf() + + local levels = folds_levels(buf) or {} + + return levels[lnum] or "0" +end + +return M diff --git a/lua/nvim-treesitter/health.lua b/lua/nvim-treesitter/health.lua index 11e899f2d..9501008df 100644 --- a/lua/nvim-treesitter/health.lua +++ b/lua/nvim-treesitter/health.lua @@ -1,174 +1,171 @@ -local parsers = require('nvim-treesitter.parsers') -local config = require('nvim-treesitter.config') -local util = require('nvim-treesitter.util') -local tsq = vim.treesitter.query -local health = vim.health +local api = vim.api +local fn = vim.fn + +local queries = require "nvim-treesitter.query" +local info = require "nvim-treesitter.info" +local shell = require "nvim-treesitter.shell_command_selectors" +local install = require "nvim-treesitter.install" +local utils = require "nvim-treesitter.utils" + +local health = vim.health or require "health" local M = {} local NVIM_TREESITTER_MINIMUM_ABI = 13 -local TREE_SITTER_MIN_VER = { 0, 26, 1 } - ----@param name string ----@return table? -local function check_exe(name) - if vim.fn.executable(name) == 1 then - local path = vim.fn.exepath(name) - local out = vim.trim(vim.fn.system({ name, '--version' })) - local version = vim.version.parse(out) - return { path = path, version = version, out = out } - end -end local function install_health() - health.start('Requirements') + health.report_start "Installation" - do -- nvim check - if vim.fn.has('nvim-0.12') ~= 1 then - health.error('Nvim-treesitter requires Neovim 0.12.0 or later.') - end + if fn.has "nvim-0.7" == 0 then + health.report_error "Nvim-treesitter requires Neovim 0.7.0+" + end + if fn.executable "tree-sitter" == 0 then + health.report_warn( + "`tree-sitter` executable not found (parser generator, only needed for :TSInstallFromGrammar," + .. " not required for :TSInstall)" + ) + else + health.report_ok( + "`tree-sitter` found " + .. (utils.ts_cli_version() or "(unknown version)") + .. " (parser generator, only needed for :TSInstallFromGrammar)" + ) + end + + if fn.executable "node" == 0 then + health.report_warn( + "`node` executable not found (only needed for :TSInstallFromGrammar," .. " not required for :TSInstall)" + ) + else + local handle = io.popen "node --version" + local result = handle:read "*a" + handle:close() + local version = vim.split(result, "\n")[1] + health.report_ok("`node` found " .. version .. " (only needed for :TSInstallFromGrammar)") + end + + if fn.executable "git" == 0 then + health.report_error("`git` executable not found.", { + "Install it with your package manager.", + "Check that your `$PATH` is set correctly.", + }) + else + health.report_ok "`git` executable found." + end + + local cc = shell.select_executable(install.compilers) + if not cc then + health.report_error("`cc` executable not found.", { + "Check that any of " + .. vim.inspect(install.compilers) + .. " is in your $PATH" + .. ' or set the environment variable CC or `require"nvim-treesitter.install".compilers` explicitly!', + }) + else + local version = vim.fn.systemlist(cc .. (cc == "cl" and "" or " --version"))[1] + health.report_ok( + "`" + .. cc + .. "` executable found. Selected from " + .. vim.inspect(install.compilers) + .. (version and ("\nVersion: " .. version) or "") + ) + end + if vim.treesitter.language_version then if vim.treesitter.language_version >= NVIM_TREESITTER_MINIMUM_ABI then - health.ok( - 'Neovim was compiled with tree-sitter runtime ABI version ' + health.report_ok( + "Neovim was compiled with tree-sitter runtime ABI version " .. vim.treesitter.language_version - .. ' (required >=' + .. " (required >=" .. NVIM_TREESITTER_MINIMUM_ABI - .. ').' + .. "). Parsers must be compatible with runtime ABI." ) else - health.error( - 'Neovim was compiled with tree-sitter runtime ABI version ' + health.report_error( + "Neovim was compiled with tree-sitter runtime ABI version " .. vim.treesitter.language_version - .. '.\n' - .. 'nvim-treesitter expects at least ABI version ' + .. ".\n" + .. "nvim-treesitter expects at least ABI version " .. NVIM_TREESITTER_MINIMUM_ABI - .. '\n' - .. 'Please make sure that Neovim is linked against a recent tree-sitter library when building' - .. ' or raise an issue at your Neovim packager. Parsers must be compatible with runtime ABI.' + .. "\n" + .. "Please make sure that Neovim is linked against are recent tree-sitter runtime when building" + .. " or raise an issue at your Neovim packager. Parsers must be compatible with runtime ABI." ) end end - do -- treesitter check - local ts = check_exe('tree-sitter') - if ts then - if vim.version.ge(ts.version, TREE_SITTER_MIN_VER) then - health.ok(string.format('tree-sitter-cli %s (%s)', ts.version, ts.path)) - else - health.error( - string.format('tree-sitter-cli v%d.%d.%d is required', unpack(TREE_SITTER_MIN_VER)) - ) - end - else - health.error('tree-sitter-cli not found') - end - end - - do -- curl+tar check - local tar = check_exe('tar') - if tar then - health.ok(string.format('tar %s (%s)', tar.version, tar.path)) - else - health.error('tar not found') - end - - local curl = check_exe('curl') - if curl then - health.ok(string.format('curl %s (%s)\n%s', curl.version, curl.path, curl.out)) - else - health.error('curl not found') - end - end - - health.start('OS Info') - local osinfo = vim.uv.os_uname() ---@type table - for k, v in pairs(osinfo) do - health.info(k .. ': ' .. v) - end - - local installdir = config.get_install_dir('') - health.start('Install directory for parsers and queries') - health.info(installdir) - if vim.uv.fs_access(installdir, 'w') then - health.ok('is writable.') - else - health.error('is not writable.') - end - if - vim.list_contains(vim.tbl_map(vim.fs.normalize, vim.api.nvim_list_runtime_paths()), installdir) - then - health.ok('is in runtimepath.') - else - health.error('is not in runtimepath.') - end + health.report_start("OS Info:\n" .. vim.inspect(vim.loop.os_uname())) end local function query_status(lang, query_group) - local ok, err = pcall(tsq.get, lang, query_group) + local ok, err = pcall(queries.get_query, lang, query_group) if not ok then - return 'x', err + return "x", err elseif not err then - return '.' + return "." else - return '✓' + return "✓" end end function M.check() - --- @type {[1]: string, [2]: string, [3]: string}[] local error_collection = {} -- Installation dependency checks install_health() - + queries.invalidate_query_cache() -- Parser installation checks - health.start('Installed languages' .. string.rep(' ', 5) .. 'H L F I J') - local languages = config.get_installed() - table.sort(languages) - for _, lang in ipairs(languages) do - local parser = parsers[lang] - local out = lang .. string.rep(' ', 22 - #lang) - if parser and parser.install_info then - for _, query_group in pairs(M.bundled_queries) do - local status, err = query_status(lang, query_group) - out = out .. status .. ' ' - if err then - table.insert(error_collection, { lang, query_group, err }) - end - end - end - if parser and parser.requires then - for _, p in pairs(parser.requires) do - if not vim.list_contains(languages, p) then - table.insert(error_collection, { lang, 'queries', 'dependency ' .. p .. ' missing' }) - end - end - end - health.info(vim.fn.trim(out, ' ', 2)) - end - health.start(' Legend: [H]ighlights, [L]ocals, [F]olds, [I]ndents, In[J]ections') + local parser_installation = { "Parser/Features H L F I J" } + for _, parser_name in pairs(info.installed_parsers()) do + local installed = #api.nvim_get_runtime_file("parser/" .. parser_name .. ".so", false) + -- Only append information about installed parsers + if installed >= 1 then + local multiple_parsers = installed > 1 and "+" or "" + local out = " - " .. parser_name .. multiple_parsers .. string.rep(" ", 15 - (#parser_name + #multiple_parsers)) + for _, query_group in pairs(queries.built_in_query_groups) do + local status, err = query_status(parser_name, query_group) + out = out .. status .. " " + if err then + table.insert(error_collection, { parser_name, query_group, err }) + end + end + table.insert(parser_installation, vim.fn.trim(out, " ", 2)) + end + end + local legend = [[ + + Legend: H[ighlight], L[ocals], F[olds], I[ndents], In[j]ections + +) multiple parsers found, only one will be used + x) errors found in the query, try to run :TSUpdate {lang}]] + table.insert(parser_installation, legend) + -- Finally call the report function + health.report_start(table.concat(parser_installation, "\n")) if #error_collection > 0 then - health.start('The following errors have been detected in query files:') + health.report_start "The following errors have been detected:" for _, p in ipairs(error_collection) do - local lang, type = p[1], p[2] + local lang, type, err = unpack(p) local lines = {} - table.insert(lines, lang .. '(' .. type .. '): ') - local files = tsq.get_files(lang, type) + table.insert(lines, lang .. "(" .. type .. "): " .. err) + local files = vim.treesitter.query.get_query_files(lang, type) if #files > 0 then + table.insert(lines, lang .. "(" .. type .. ") is concatenated from the following files:") for _, file in ipairs(files) do - local query = util.read_file(file) - local _, file_err = pcall(tsq.parse, lang, query) - if file_err then - table.insert(lines, file) + local fd = io.open(file, "r") + if fd then + local ok, file_err = pcall(vim.treesitter.query.parse_query, lang, fd:read "*a") + if ok then + table.insert(lines, '| [OK]:"' .. file .. '"') + else + table.insert(lines, '| [ERROR]:"' .. file .. '", failed to load: ' .. file_err) + end + fd:close() end end end - health.error(table.concat(lines, '')) + health.report_error(table.concat(lines, "\n")) end end end -M.bundled_queries = { 'highlights', 'locals', 'folds', 'indents', 'injections' } - return M diff --git a/lua/nvim-treesitter/highlight.lua b/lua/nvim-treesitter/highlight.lua new file mode 100644 index 000000000..5f7dead61 --- /dev/null +++ b/lua/nvim-treesitter/highlight.lua @@ -0,0 +1,54 @@ +local api = vim.api +local ts = vim.treesitter + +local parsers = require "nvim-treesitter.parsers" +local configs = require "nvim-treesitter.configs" + +local M = {} + +---@param config table +---@param lang string +---@return boolean +local function should_enable_vim_regex(config, lang) + local additional_hl = config.additional_vim_regex_highlighting + local is_table = type(additional_hl) == "table" + + return additional_hl and (not is_table or vim.tbl_contains(additional_hl, lang)) +end + +---@param bufnr integer +local function enable_syntax(bufnr) + api.nvim_buf_set_option(bufnr, "syntax", "ON") +end + +---@param bufnr integer +function M.stop(bufnr) + if ts.highlighter.active[bufnr] then + ts.highlighter.active[bufnr]:destroy() + end +end + +---@param bufnr integer +---@param lang string +function M.start(bufnr, lang) + local parser = parsers.get_parser(bufnr, lang) + ts.highlighter.new(parser, {}) +end + +---@param bufnr integer +---@param lang string +function M.attach(bufnr, lang) + local config = configs.get_module "highlight" + M.start(bufnr, lang) + if config and should_enable_vim_regex(config, lang) then + enable_syntax(bufnr) + end +end + +---@param bufnr integer +function M.detach(bufnr) + M.stop(bufnr) + enable_syntax(bufnr) +end + +return M diff --git a/lua/nvim-treesitter/incremental_selection.lua b/lua/nvim-treesitter/incremental_selection.lua new file mode 100644 index 000000000..5deaaf84e --- /dev/null +++ b/lua/nvim-treesitter/incremental_selection.lua @@ -0,0 +1,164 @@ +local api = vim.api + +local configs = require "nvim-treesitter.configs" +local ts_utils = require "nvim-treesitter.ts_utils" +local locals = require "nvim-treesitter.locals" +local parsers = require "nvim-treesitter.parsers" +local queries = require "nvim-treesitter.query" + +local M = {} + +local selections = {} + +function M.init_selection() + local buf = api.nvim_get_current_buf() + local node = ts_utils.get_node_at_cursor() + selections[buf] = { [1] = node } + ts_utils.update_selection(buf, node) +end + +--- Get the range of the current visual selection. +-- +-- The range start with 1 and the ending is inclusive. +local function visual_selection_range() + local _, csrow, cscol, _ = unpack(vim.fn.getpos "'<") + local _, cerow, cecol, _ = unpack(vim.fn.getpos "'>") + + local start_row, start_col, end_row, end_col + + if csrow < cerow or (csrow == cerow and cscol <= cecol) then + start_row = csrow + start_col = cscol + end_row = cerow + end_col = cecol + else + start_row = cerow + start_col = cecol + end_row = csrow + end_col = cscol + end + + return start_row, start_col, end_row, end_col +end + +local function range_matches(node) + local csrow, cscol, cerow, cecol = visual_selection_range() + local srow, scol, erow, ecol = ts_utils.get_vim_range { node:range() } + return srow == csrow and scol == cscol and erow == cerow and ecol == cecol +end + +local function select_incremental(get_parent) + return function() + local buf = api.nvim_get_current_buf() + local nodes = selections[buf] + + local csrow, cscol, cerow, cecol = visual_selection_range() + -- Initialize incremental selection with current selection + if not nodes or #nodes == 0 or not range_matches(nodes[#nodes]) then + local root = parsers.get_parser():parse()[1]:root() + local node = root:named_descendant_for_range(csrow - 1, cscol - 1, cerow - 1, cecol) + ts_utils.update_selection(buf, node) + if nodes and #nodes > 0 then + table.insert(selections[buf], node) + else + selections[buf] = { [1] = node } + end + return + end + + -- Find a node that changes the current selection. + local node = nodes[#nodes] + while true do + local parent = get_parent(node) + if not parent or parent == node then + -- Keep searching in the main tree + -- TODO: we should search on the parent tree of the current node. + local root = parsers.get_parser():parse()[1]:root() + parent = root:named_descendant_for_range(csrow - 1, cscol - 1, cerow - 1, cecol) + if not parent or root == node or parent == node then + ts_utils.update_selection(buf, node) + return + end + end + node = parent + local srow, scol, erow, ecol = ts_utils.get_vim_range { node:range() } + local same_range = (srow == csrow and scol == cscol and erow == cerow and ecol == cecol) + if not same_range then + table.insert(selections[buf], node) + if node ~= nodes[#nodes] then + table.insert(nodes, node) + end + ts_utils.update_selection(buf, node) + return + end + end + end +end + +M.node_incremental = select_incremental(function(node) + return node:parent() or node +end) + +M.scope_incremental = select_incremental(function(node) + local lang = parsers.get_buf_lang() + if queries.has_locals(lang) then + return locals.containing_scope(node:parent() or node) + else + return node + end +end) + +function M.node_decremental() + local buf = api.nvim_get_current_buf() + local nodes = selections[buf] + if not nodes or #nodes < 2 then + return + end + + table.remove(selections[buf]) + local node = nodes[#nodes] + ts_utils.update_selection(buf, node) +end + +local FUNCTION_DESCRIPTIONS = { + init_selection = "Start selecting nodes with nvim-treesitter", + node_incremental = "Increment selection to named node", + scope_incremental = "Increment selection to surrounding scope", + node_decremental = "Shrink selection to previous named node", +} + +function M.attach(bufnr) + local config = configs.get_module "incremental_selection" + for funcname, mapping in pairs(config.keymaps) do + local mode + local rhs + if funcname == "init_selection" then + mode = "n" + rhs = M[funcname] + else + mode = "x" + -- We need to move to command mode to access marks '< (visual area start) and '> (visual area end) which are not + -- properly accessible in visual mode. + rhs = string.format(":lua require'nvim-treesitter.incremental_selection'.%s()", funcname) + end + vim.keymap.set( + mode, + mapping, + rhs, + { buffer = bufnr, silent = true, noremap = true, desc = FUNCTION_DESCRIPTIONS[funcname] } + ) + end +end + +function M.detach(bufnr) + local config = configs.get_module "incremental_selection" + for f, mapping in pairs(config.keymaps) do + if f == "init_selection" then + vim.keymap.del("n", mapping, { buffer = bufnr }) + else + vim.keymap.del("x", mapping, { buffer = bufnr }) + end + end +end + +return M diff --git a/lua/nvim-treesitter/indent.lua b/lua/nvim-treesitter/indent.lua index ee513c351..0eac0a911 100644 --- a/lua/nvim-treesitter/indent.lua +++ b/lua/nvim-treesitter/indent.lua @@ -1,132 +1,89 @@ -local ts = vim.treesitter +local parsers = require "nvim-treesitter.parsers" +local queries = require "nvim-treesitter.query" +local tsutils = require "nvim-treesitter.ts_utils" local M = {} +M.avoid_force_reparsing = { + yaml = true, +} + M.comment_parsers = { comment = true, - luadoc = true, - javadoc = true, jsdoc = true, phpdoc = true, } -local function getline(lnum) - return vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, false)[1] or '' +local function get_first_node_at_line(root, lnum) + local col = vim.fn.indent(lnum) + return root:descendant_for_range(lnum - 1, col, lnum - 1, col) end ----@param lnum integer ----@return integer -local function get_indentcols_at_line(lnum) - local _, indentcols = getline(lnum):find('^%s*') - return indentcols or 0 +local function get_last_node_at_line(root, lnum) + local col = #vim.fn.getline(lnum) - 1 + return root:descendant_for_range(lnum - 1, col, lnum - 1, col) end ----@param root TSNode ----@param lnum integer ----@param col? integer ----@return TSNode? -local function get_first_node_at_line(root, lnum, col) - col = col or get_indentcols_at_line(lnum) - return root:descendant_for_range(lnum - 1, col, lnum - 1, col + 1) -end - ----@param root TSNode ----@param lnum integer ----@param col? integer ----@return TSNode? -local function get_last_node_at_line(root, lnum, col) - col = col or (#getline(lnum) - 1) - return root:descendant_for_range(lnum - 1, col, lnum - 1, col + 1) -end - ----@param bufnr integer ----@param node TSNode ----@param delimiter string ----@return TSNode? child ----@return boolean? is_end local function find_delimiter(bufnr, node, delimiter) for child, _ in node:iter_children() do if child:type() == delimiter then local linenr = child:start() local line = vim.api.nvim_buf_get_lines(bufnr, linenr, linenr + 1, false)[1] local end_char = { child:end_() } - local trimmed_after_delim - local escaped_delimiter = delimiter:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]', '%%%1') - trimmed_after_delim = - assert(line):sub(end_char[2] + 1):gsub('[%s' .. escaped_delimiter .. ']*', '') - return child, #trimmed_after_delim == 0 + return child, #line == end_char[2] end end end ----Memoize a function using hash_fn to hash the arguments. ----@generic F: function ----@param fn F ----@param hash_fn fun(...): any ----@return F -local function memoize(fn, hash_fn) - local cache = setmetatable({}, { __mode = 'kv' }) ---@type table - - return function(...) - local key = hash_fn(...) - if cache[key] == nil then - local v = fn(...) ---@type any - cache[key] = v ~= nil and v or vim.NIL - end - - local v = cache[key] - return v ~= vim.NIL and v or nil - end -end - -local get_indents = memoize(function(bufnr, root, lang) - ---@type table> +local get_indents = tsutils.memoize_by_buf_tick(function(bufnr, root, lang) local map = { - ['indent.auto'] = {}, - ['indent.begin'] = {}, - ['indent.end'] = {}, - ['indent.dedent'] = {}, - ['indent.branch'] = {}, - ['indent.ignore'] = {}, - ['indent.align'] = {}, - ['indent.zero'] = {}, + auto = {}, + indent = {}, + indent_end = {}, + dedent = {}, + branch = {}, + ignore = {}, + aligned_indent = {}, + zero_indent = {}, } - local query = ts.query.get(lang, 'indents') - if not query then - return map - end - for id, node, metadata in query:iter_captures(root, bufnr) do - if assert(query.captures[id]):sub(1, 1) ~= '_' then - map[query.captures[id]][node:id()] = metadata or {} - end + for name, node, metadata in queries.iter_captures(bufnr, "indents", root, lang) do + map[name][node:id()] = metadata or {} end return map -end, function(bufnr, root, lang) - return tostring(bufnr) .. root:id() .. '_' .. lang -end) +end, { + -- Memoize by bufnr and lang together. + key = function(bufnr, root, lang) + return tostring(bufnr) .. root:id() .. "_" .. lang + end, +}) ----@param lnum integer (1-indexed) ----@return integer +---@param lnum number (1-indexed) function M.get_indent(lnum) local bufnr = vim.api.nvim_get_current_buf() - local parser = ts.get_parser(bufnr) + local parser = parsers.get_parser(bufnr) if not parser or not lnum then return -1 end - parser:parse({ vim.fn.line('w0') - 1, vim.fn.line('w$') }) + local root_lang = parsers.get_buf_lang(bufnr) + + -- some languages like Python will actually have worse results when re-parsing at opened new line + if not M.avoid_force_reparsing[root_lang] then + -- Reparse in case we got triggered by ":h indentkeys" + parser:parse() + end -- Get language tree with smallest range around node that's not a comment parser - local root, lang_tree ---@type TSNode, vim.treesitter.LanguageTree + local root, lang_tree parser:for_each_tree(function(tstree, tree) if not tstree or M.comment_parsers[tree:lang()] then return end local local_root = tstree:root() - if ts.is_in_node_range(local_root, lnum - 1, 0) then - if not root or root:byte_length() >= local_root:byte_length() then + if tsutils.is_in_node_range(local_root, lnum - 1, 0) then + if not root or tsutils.node_length(root) >= tsutils.node_length(local_root) then root = local_root lang_tree = tree end @@ -139,27 +96,12 @@ function M.get_indent(lnum) end local q = get_indents(vim.api.nvim_get_current_buf(), root, lang_tree:lang()) - local node ---@type TSNode? - if getline(lnum):find('^%s*$') then + local is_empty_line = string.match(vim.fn.getline(lnum), "^%s*$") ~= nil + local node + if is_empty_line then local prevlnum = vim.fn.prevnonblank(lnum) - local indentcols = get_indentcols_at_line(prevlnum) - local prevline = vim.trim(getline(prevlnum)) - -- The final position can be trailing spaces, which should not affect indentation - node = get_last_node_at_line(root, prevlnum, indentcols + #prevline - 1) - if node and node:type():match('comment') then - -- The final node we capture of the previous line can be a comment node, which should also be ignored - -- Unless the last line is an entire line of comment, ignore the comment range and find the last node again - local first_node = get_first_node_at_line(root, prevlnum, indentcols) - local _, scol, _, _ = node:range() - if first_node and first_node:id() ~= node:id() then - -- In case the last captured node is a trailing comment node, re-trim the string - prevline = vim.trim(prevline:sub(1, scol - indentcols)) - -- Add back indent as indent of prevline was trimmed away - local col = indentcols + #prevline - 1 - node = get_last_node_at_line(root, prevlnum, col) - end - end - if node and q['indent.end'][node:id()] then + node = get_last_node_at_line(root, prevlnum) + if q.indent_end[node:id()] then node = get_first_node_at_line(root, lnum) end else @@ -175,33 +117,22 @@ function M.get_indent(lnum) end -- tracks to ensure multiple indent levels are not applied for same line - local is_processed_by_row = {} --- @type table + local is_processed_by_row = {} - if node and q['indent.zero'][node:id()] then + if q.zero_indent[node:id()] then return 0 end while node do -- do 'autoindent' if not marked as @indent - if - not q['indent.begin'][node:id()] - and not q['indent.align'][node:id()] - and q['indent.auto'][node:id()] - and node:start() < lnum - 1 - and lnum - 1 <= node:end_() - then + if not q.indent[node:id()] and q.auto[node:id()] and node:start() < lnum - 1 and lnum - 1 <= node:end_() then return -1 end -- Do not indent if we are inside an @ignore block. -- If a node spans from L1,C1 to L2,C2, we know that lines where L1 < line <= L2 would -- have their indentations contained by the node. - if - not q['indent.begin'][node:id()] - and q['indent.ignore'][node:id()] - and node:start() < lnum - 1 - and lnum - 1 <= node:end_() - then + if not q.indent[node:id()] and q.ignore[node:id()] and node:start() < lnum - 1 and lnum - 1 <= node:end_() then return 0 end @@ -211,10 +142,7 @@ function M.get_indent(lnum) if not is_processed_by_row[srow] - and ( - (q['indent.branch'][node:id()] and srow == lnum - 1) - or (q['indent.dedent'][node:id()] and srow ~= lnum - 1) - ) + and ((q.branch[node:id()] and srow == lnum - 1) or (q.dedent[node:id()] and srow ~= lnum - 1)) then indent = indent - indent_size is_processed = true @@ -225,112 +153,38 @@ function M.get_indent(lnum) local is_in_err = false if should_process then local parent = node:parent() - is_in_err = parent and parent:has_error() or false + is_in_err = parent and parent:has_error() end if should_process and ( - q['indent.begin'][node:id()] - and (srow ~= erow or is_in_err or q['indent.begin'][node:id()]['indent.immediate']) - and (srow ~= lnum - 1 or q['indent.begin'][node:id()]['indent.start_at_same_line']) + q.indent[node:id()] + and (srow ~= erow or is_in_err) + and (srow ~= lnum - 1 or q.indent[node:id()].start_at_same_line) ) then indent = indent + indent_size is_processed = true end - if is_in_err and not q['indent.align'][node:id()] then - -- only when the node is in error, promote the - -- first child's aligned indent to the error node - -- to work around ((ERROR "X" . (_)) @aligned_indent (#set! "delimiter" "AB")) - -- matching for all X, instead set do - -- (ERROR "X" @aligned_indent (#set! "delimiter" "AB") . (_)) - -- and we will fish it out here. - for c in node:iter_children() do - if q['indent.align'][c:id()] then - q['indent.align'][node:id()] = q['indent.align'][c:id()] - break - end - end - end -- do not indent for nodes that starts-and-ends on same line and starts on target line (lnum) - if - should_process - and q['indent.align'][node:id()] - and (srow ~= erow or is_in_err) - and (srow ~= lnum - 1) - then - local metadata = q['indent.align'][node:id()] - local o_delim_node, o_is_last_in_line ---@type TSNode?, boolean? - local c_delim_node, c_is_last_in_line ---@type TSNode?, boolean?, boolean? - local indent_is_absolute = false - if metadata['indent.open_delimiter'] then - o_delim_node, o_is_last_in_line = - find_delimiter(bufnr, node, metadata['indent.open_delimiter']) + if q.aligned_indent[node:id()] and srow ~= erow and (srow ~= lnum - 1) then + local metadata = q.aligned_indent[node:id()] + local o_delim_node, is_last_in_line + if metadata.delimiter then + local opening_delimiter = metadata.delimiter and metadata.delimiter:sub(1, 1) + o_delim_node, is_last_in_line = find_delimiter(bufnr, node, opening_delimiter) else o_delim_node = node end - if metadata['indent.close_delimiter'] then - c_delim_node, c_is_last_in_line = - find_delimiter(bufnr, node, metadata['indent.close_delimiter']) - else - c_delim_node = node - end if o_delim_node then - local o_srow, o_scol = o_delim_node:start() - local c_srow = nil --- @type integer? - if c_delim_node then - c_srow = c_delim_node:start() - end - if o_is_last_in_line then + if is_last_in_line then -- hanging indent (previous line ended with starting delimiter) - -- should be processed like indent - if should_process then - indent = indent + indent_size * 1 - if c_is_last_in_line then - -- If current line is outside the range of a node marked with `@aligned_indent` - -- Then its indent level shouldn't be affected by `@aligned_indent` node - if c_srow and c_srow < lnum - 1 then - indent = math.max(indent - indent_size, 0) - end - end - end + indent = indent + indent_size * 1 else - -- aligned indent - if c_is_last_in_line and c_srow and o_srow ~= c_srow and c_srow < lnum - 1 then - -- If current line is outside the range of a node marked with `@aligned_indent` - -- Then its indent level shouldn't be affected by `@aligned_indent` node - indent = math.max(indent - indent_size, 0) - else - indent = o_scol + (metadata['indent.increment'] or 1) - indent_is_absolute = true - end - end - -- deal with the final line - local avoid_last_matching_next = false - if c_srow and c_srow ~= o_srow and c_srow == lnum - 1 then - -- delims end on current line, and are not open and closed same line. - -- then this last line may need additional indent to avoid clashes - -- with the next. `indent.avoid_last_matching_next` controls this behavior, - -- for example this is needed for function parameters. - avoid_last_matching_next = metadata['indent.avoid_last_matching_next'] or false - end - if avoid_last_matching_next then - -- last line must be indented more in cases where - -- it would be same indent as next line (we determine this as one - -- width more than the open indent to avoid confusing with any - -- hanging indents) - if indent <= vim.fn.indent(o_srow + 1) + indent_size then - indent = indent + indent_size * 1 - else - indent = indent - end - end - is_processed = true - if indent_is_absolute then - -- don't allow further indenting by parent nodes, this is an absolute position - return indent + local _, o_scol = o_delim_node:start() + return math.max(indent, 0) + o_scol + (metadata.increment or 1) end end end @@ -343,4 +197,15 @@ function M.get_indent(lnum) return indent end +local indent_funcs = {} + +function M.attach(bufnr) + indent_funcs[bufnr] = vim.bo.indentexpr + vim.bo.indentexpr = "nvim_treesitter#indent()" +end + +function M.detach(bufnr) + vim.bo.indentexpr = indent_funcs[bufnr] +end + return M diff --git a/lua/nvim-treesitter/info.lua b/lua/nvim-treesitter/info.lua new file mode 100644 index 000000000..eaeb9751c --- /dev/null +++ b/lua/nvim-treesitter/info.lua @@ -0,0 +1,179 @@ +local api = vim.api +local configs = require "nvim-treesitter.configs" +local parsers = require "nvim-treesitter.parsers" + +local M = {} + +local function install_info() + local max_len = 0 + for _, ft in pairs(parsers.available_parsers()) do + if #ft > max_len then + max_len = #ft + end + end + + local parser_list = parsers.available_parsers() + table.sort(parser_list) + for _, lang in pairs(parser_list) do + local is_installed = #api.nvim_get_runtime_file("parser/" .. lang .. ".so", false) > 0 + api.nvim_out_write(lang .. string.rep(" ", max_len - #lang + 1)) + if is_installed then + api.nvim_out_write "[✓] installed\n" + elseif pcall(vim.treesitter.inspect_lang, lang) then + api.nvim_out_write "[✗] not installed (but still loaded. Restart Neovim!)\n" + else + api.nvim_out_write "[✗] not installed\n" + end + end +end + +-- Sort a list of modules into namespaces. +-- {'mod1', 'mod2.sub1', 'mod2.sub2', 'mod3'} +-- -> +-- { default = {'mod1', 'mod3'}, mod2 = {'sub1', 'sub2'}} +local function namespace_modules(modulelist) + local modules = {} + for _, module in ipairs(modulelist) do + if module:find "%." then + local namespace, submodule = module:match "^(.*)%.(.*)$" + if not modules[namespace] then + modules[namespace] = {} + end + table.insert(modules[namespace], submodule) + else + if not modules.default then + modules.default = {} + end + table.insert(modules.default, module) + end + end + return modules +end + +local function longest_string_length(list) + local length = 0 + for _, value in ipairs(list) do + if #value > length then + length = #value + end + end + return length +end + +local function append_module_table(curbuf, origbuf, parserlist, namespace, modulelist) + local maxlen_parser = longest_string_length(parserlist) + table.sort(modulelist) + + -- header + local header = ">> " .. namespace .. string.rep(" ", maxlen_parser - #namespace - 1) + for _, module in pairs(modulelist) do + header = header .. module .. " " + end + api.nvim_buf_set_lines(curbuf, -1, -1, true, { header }) + + -- actual table + for _, parser in ipairs(parserlist) do + local padding = string.rep(" ", maxlen_parser - #parser + 2) + local line = parser .. padding + local namespace_prefix = (namespace == "default") and "" or namespace .. "." + for _, module in pairs(modulelist) do + local modlen = #module + module = namespace_prefix .. module + if configs.is_enabled(module, parser, origbuf) then + line = line .. "✓" + else + line = line .. "✗" + end + line = line .. string.rep(" ", modlen + 1) + end + api.nvim_buf_set_lines(curbuf, -1, -1, true, { line }) + end + + api.nvim_buf_set_lines(curbuf, -1, -1, true, { "" }) +end + +local function print_info_modules(parserlist, module) + local origbuf = api.nvim_get_current_buf() + api.nvim_command "enew" + local curbuf = api.nvim_get_current_buf() + + local modules + if module then + modules = namespace_modules { module } + else + modules = namespace_modules(configs.available_modules()) + end + + local namespaces = {} + for k, _ in pairs(modules) do + table.insert(namespaces, k) + end + table.sort(namespaces) + + table.sort(parserlist) + for _, namespace in ipairs(namespaces) do + append_module_table(curbuf, origbuf, parserlist, namespace, modules[namespace]) + end + + api.nvim_buf_set_option(curbuf, "modified", false) + api.nvim_buf_set_option(curbuf, "buftype", "nofile") + vim.cmd [[ + syntax match TSModuleInfoGood /✓/ + syntax match TSModuleInfoBad /✗/ + syntax match TSModuleInfoHeader /^>>.*$/ contains=TSModuleInfoNamespace + syntax match TSModuleInfoNamespace /^>> \w*/ contained + syntax match TSModuleInfoParser /^[^> ]*\ze / + ]] + + local highlights = { + TSModuleInfoGood = { fg = "LightGreen", bold = true, default = true }, + TSModuleInfoBad = { fg = "Crimson", default = true }, + TSModuleInfoHeader = { link = "Type", default = true }, + TSModuleInfoNamespace = { link = "Statement", default = true }, + TSModuleInfoParser = { link = "Identifier", default = true }, + } + for k, v in pairs(highlights) do + api.nvim_set_hl(0, k, v) + end +end + +local function module_info(module) + if module and not configs.get_module(module) then + return + end + + local parserlist = parsers.available_parsers() + if module then + print_info_modules(parserlist, module) + else + print_info_modules(parserlist) + end +end + +function M.installed_parsers() + local installed = {} + for _, p in pairs(parsers.available_parsers()) do + if parsers.has_parser(p) then + table.insert(installed, p) + end + end + return installed +end + +M.commands = { + TSInstallInfo = { + run = install_info, + args = { + "-nargs=0", + }, + }, + TSModuleInfo = { + run = module_info, + args = { + "-nargs=?", + "-complete=custom,nvim_treesitter#available_modules", + }, + }, +} + +return M diff --git a/lua/nvim-treesitter/init.lua b/lua/nvim-treesitter/init.lua deleted file mode 100644 index c5a9201f3..000000000 --- a/lua/nvim-treesitter/init.lua +++ /dev/null @@ -1,31 +0,0 @@ -local M = {} - -function M.setup(...) - require('nvim-treesitter.config').setup(...) -end - -function M.get_available(...) - return require('nvim-treesitter.config').get_available(...) -end - -function M.get_installed(...) - return require('nvim-treesitter.config').get_installed(...) -end - -function M.install(...) - return require('nvim-treesitter.install').install(...) -end - -function M.uninstall(...) - return require('nvim-treesitter.install').uninstall(...) -end - -function M.update(...) - return require('nvim-treesitter.install').update(...) -end - -function M.indentexpr() - return require('nvim-treesitter.indent').get_indent(vim.v.lnum) -end - -return M diff --git a/lua/nvim-treesitter/install.lua b/lua/nvim-treesitter/install.lua index 71d5a3c76..b0428bd8f 100644 --- a/lua/nvim-treesitter/install.lua +++ b/lua/nvim-treesitter/install.lua @@ -1,649 +1,699 @@ +local api = vim.api local fn = vim.fn -local fs = vim.fs -local uv = vim.uv +local luv = vim.loop -local a = require('nvim-treesitter.async') -local config = require('nvim-treesitter.config') -local log = require('nvim-treesitter.log') -local parsers = require('nvim-treesitter.parsers') -local util = require('nvim-treesitter.util') - ----@type fun(path: string, new_path: string, flags?: table): string? -local uv_copyfile = a.awrap(4, uv.fs_copyfile) - ----@type fun(path: string, mode: integer): string? -local uv_mkdir = a.awrap(3, uv.fs_mkdir) - ----@type fun(path: string): string? -local uv_rmdir = a.awrap(2, uv.fs_rmdir) - ----@type fun(path: string, new_path: string): string? -local uv_rename = a.awrap(3, uv.fs_rename) - ----@type fun(path: string, new_path: string, flags?: table): string? -local uv_symlink = a.awrap(4, uv.fs_symlink) - ----@type fun(path: string): string? -local uv_unlink = a.awrap(2, uv.fs_unlink) - ----@async ----@param path string ----@return string? err -local function mkpath(path) - local parent = fs.dirname(path) - if not parent:match('^[./]$') and not uv.fs_stat(parent) then - mkpath(parent) - end - - return uv_mkdir(path, 493) -- tonumber('755', 8) -end - ----@async ----@param path string ----@return string? err -local function rmpath(path) - local stat = uv.fs_lstat(path) - if not stat then - return - end - - if stat.type == 'directory' then - for file in fs.dir(path) do - rmpath(fs.joinpath(path, file)) - end - return uv_rmdir(path) - else - return uv_unlink(path) - end -end - -local MAX_JOBS = 100 -local INSTALL_TIMEOUT = 60000 - ---- @async ---- @param max_jobs integer ---- @param tasks async.TaskFun[] -local function join(max_jobs, tasks) - if #tasks == 0 then - return - end - - max_jobs = math.min(max_jobs, #tasks) - - local remaining = { select(max_jobs + 1, unpack(tasks)) } - local to_go = #tasks - - a.await(1, function(finish) - local function cb() - to_go = to_go - 1 - if to_go == 0 then - finish() - elseif #remaining > 0 then - local next_task = table.remove(remaining) - next_task():await(cb) - end - end - - for i = 1, max_jobs do - assert(tasks[i]) - tasks[i]():await(cb) - end - end) -end - ----@async ----@param cmd string[] ----@param opts? vim.SystemOpts ----@return vim.SystemCompleted -local function system(cmd, opts) - local cwd = opts and opts.cwd or uv.cwd() - log.trace('running job: (cwd=%s) %s', cwd, table.concat(cmd, ' ')) - - ---vim.system throws an error when uv.spawn fails, in particular if cmd or cwd - ---does not exist. This kills the coroutine, so the async'ed call simply hangs. - ---Instead, we pass a wrapper that catches errors and propagates them as a proper - ---`SystemObj`. - ---TODO(clason): remove when https://github.com/neovim/neovim/issues/38257 is resolved. - ---@param _cmd string[] - ---@param _opts vim.SystemOpts - ---@param on_exit fun(result: vim.SystemCompleted) - ---@return vim.SystemObj? - local function system_wrap(_cmd, _opts, on_exit) - local ok, ret = pcall(vim.system, _cmd, _opts, on_exit) - if not ok then - on_exit({ - code = 125, - signal = 0, - stdout = '', - stderr = ret --[[@as string]], - }) - return nil - end - return ret --[[@as vim.SystemObj]] - end - - local r = a.await(3, system_wrap, cmd, opts) --[[@as vim.SystemCompleted]] - a.schedule() - if r.stdout and r.stdout ~= '' then - log.trace('stdout -> %s', r.stdout) - end - if r.stderr and r.stderr ~= '' then - log.trace('stderr -> %s', r.stderr) - end - - return r -end +local utils = require "nvim-treesitter.utils" +local parsers = require "nvim-treesitter.parsers" +local info = require "nvim-treesitter.info" +local configs = require "nvim-treesitter.configs" +local shell = require "nvim-treesitter.shell_command_selectors" local M = {} +local lockfile = {} ---- ---- PARSER INFO ---- +M.compilers = { vim.fn.getenv "CC", "cc", "gcc", "clang", "cl", "zig" } +M.prefer_git = fn.has "win32" == 1 +M.command_extra_args = {} +M.ts_generate_args = nil ----@param lang string ----@return InstallInfo? -local function get_parser_install_info(lang) - local parser_config = parsers[lang] +local started_commands = 0 +local finished_commands = 0 +local failed_commands = 0 +local complete_std_output = {} +local complete_error_output = {} - if not parser_config then - log.error('Parser not available for language "' .. lang .. '"') +local function reset_progress_counter() + if started_commands ~= finished_commands then return end - - return parser_config.install_info + started_commands = 0 + finished_commands = 0 + failed_commands = 0 + complete_std_output = {} + complete_error_output = {} end ----@param ... string ----@return string -function M.get_package_path(...) - local info = assert(debug.getinfo(1, 'S')) - return fs.joinpath(fn.fnamemodify(info.source:sub(2), ':p:h:h:h'), ...) +local function get_job_status() + return "[nvim-treesitter] [" + .. finished_commands + .. "/" + .. started_commands + .. (failed_commands > 0 and ", failed: " .. failed_commands or "") + .. "]" end ---@param lang string ----@return string? +---@param validate boolean|nil +---@return InstallInfo +local function get_parser_install_info(lang, validate) + local parser_config = parsers.get_parser_configs()[lang] + + if not parser_config then + error('Parser not available for language "' .. lang .. '"') + end + + local install_info = parser_config.install_info + + if validate then + vim.validate { + url = { install_info.url, "string" }, + files = { install_info.files, "table" }, + } + end + + return install_info +end + +local function load_lockfile() + local filename = utils.join_path(utils.get_package_path(), "lockfile.json") + lockfile = vim.fn.filereadable(filename) == 1 and vim.fn.json_decode(vim.fn.readfile(filename)) or {} +end + +local function is_ignored_parser(lang) + return vim.tbl_contains(configs.get_ignored_parser_installs(), lang) +end + +local function get_revision(lang) + if #lockfile == 0 then + load_lockfile() + end + + local install_info = get_parser_install_info(lang) + if install_info.revision then + return install_info.revision + end + + return (lockfile[lang] and lockfile[lang].revision) +end + +---@param lang string +---@return string|nil local function get_installed_revision(lang) - local lang_file = fs.joinpath(config.get_install_dir('parser-info'), lang .. '.revision') - return util.read_file(lang_file) + local lang_file = utils.join_path(configs.get_parser_info_dir(), lang .. ".revision") + if vim.fn.filereadable(lang_file) == 1 then + return vim.fn.readfile(lang_file)[1] + end +end + +---Checks if parser is installed with nvim-treesitter +---@param lang string +---@return boolean +local function is_installed(lang) + local matched_parsers = vim.api.nvim_get_runtime_file("parser/" .. lang .. ".so", true) or {} + local install_dir = configs.get_parser_install_dir() + if not install_dir then + return false + end + install_dir = vim.fn.fnamemodify(install_dir, ":p") + for _, path in ipairs(matched_parsers) do + local abspath = vim.fn.fnamemodify(path, ":p") + if vim.startswith(abspath, install_dir) then + return true + end + end + return false end ---@param lang string ---@return boolean local function needs_update(lang) - local info = get_parser_install_info(lang) - if info and info.revision then - return info.revision ~= get_installed_revision(lang) - end - - -- No revision. Check the queries link to the same place - - local queries = fs.joinpath(config.get_install_dir('queries'), lang) - local queries_src = M.get_package_path('runtime', 'queries', lang) - - return uv.fs_realpath(queries) ~= uv.fs_realpath(queries_src) + local revision = get_revision(lang) + return not revision or revision ~= get_installed_revision(lang) end ---- ---- PARSER MANAGEMENT FUNCTIONS ---- - ----@async ----@param logger Logger ----@param repo InstallInfo ----@param compile_location string ----@return string? err -local function do_generate(logger, repo, compile_location) - local from_json = true - if repo.generate_from_json == false then - from_json = false - end - - logger:info( - string.format('Generating parser.c from %s...', from_json and 'grammar.json' or 'grammar.js') - ) - - local r = system({ - 'tree-sitter', - 'generate', - '--abi', - tostring(vim.treesitter.language_version), - from_json and 'src/grammar.json' or nil, - }, { cwd = compile_location, env = { TREE_SITTER_JS_RUNTIME = 'native' } }) - if r.code > 0 then - return logger:error('Error during "tree-sitter generate": %s', r.stderr) - end +---@return table +local function outdated_parsers() + return vim.tbl_filter(function(lang) + return is_installed(lang) and needs_update(lang) + end, info.installed_parsers()) end ----@async ----@param logger Logger ----@param url string ----@param project_name string ----@param cache_dir string ----@param revision string ----@param output_dir string ----@return string? err -local function do_download(logger, url, project_name, cache_dir, revision, output_dir) - local tmp = output_dir .. '-tmp' - - rmpath(tmp) - a.schedule() - - url = url:gsub('.git$', '') - local target = string.format('%s/archive/%s.tar.gz', url, revision) - - local tarball_path = fs.joinpath(cache_dir, project_name .. '.tar.gz') - - do -- Download tarball - logger:info('Downloading %s...', project_name) - local r = system({ - 'curl', - '--silent', - '--fail', - '--show-error', - '--retry', - '7', - '-L', -- follow redirects - target, - '--output', - tarball_path, - }) - if r.code > 0 then - return logger:error('Error during download: %s', r.stderr) +---@param handle userdata +---@param is_stderr boolean +local function onread(handle, is_stderr) + return function(_, data) + if data then + if is_stderr then + complete_error_output[handle] = (complete_error_output[handle] or "") .. data + else + complete_std_output[handle] = (complete_std_output[handle] or "") .. data + end end end - - do -- Create tmp dir - logger:debug('Creating temporary directory: %s', tmp) - local err = mkpath(tmp) - a.schedule() - if err then - return logger:error('Could not create %s-tmp: %s', project_name, err) - end - end - - do -- Extract tarball - logger:debug('Extracting %s into %s...', tarball_path, project_name) - -- Windows tar can't handle drive letters - local r = system( - { 'tar', '-xzf', project_name .. '.tar.gz', '-C', project_name .. '-tmp' }, - { cwd = cache_dir } - ) - if r.code > 0 then - return logger:error('Error during tarball extraction: %s', r.stderr) - end - end - - do -- Remove tarball - logger:debug('Removing %s...', tarball_path) - local err = uv_unlink(tarball_path) - a.schedule() - if err then - return logger:error('Could not remove tarball: %s', err) - end - end - - do -- Move tmp dir to output dir - local dir_rev = revision:find('^v%d') and revision:sub(2) or revision - local repo_project_name = url:match('[^/]-$') - local extracted = fs.joinpath(tmp, repo_project_name .. '-' .. dir_rev) - logger:debug('Moving %s to %s/...', extracted, output_dir) - local err = uv_rename(extracted, output_dir) - a.schedule() - if err then - return logger:error('Could not rename temp: %s', err) - end - end - - rmpath(tmp) - a.schedule() end ----@async ----@param logger Logger ----@param compile_location string ----@return string? err -local function do_compile(logger, compile_location) - logger:info(string.format('Compiling parser')) - - local r = system({ - 'tree-sitter', - 'build', - '-o', - 'parser.so', - }, { cwd = compile_location }) - if r.code > 0 then - return logger:error('Error during "tree-sitter build": %s', r.stderr) +function M.iter_cmd(cmd_list, i, lang, success_message) + if i == 1 then + started_commands = started_commands + 1 end -end - ----@async ----@param logger Logger ----@param compile_location string ----@param target_location string ----@return string? err -local function do_install(logger, compile_location, target_location) - logger:info(string.format('Installing parser')) - - local tempfile = target_location .. tostring(uv.hrtime()) - uv_rename(target_location, tempfile) -- parser may be in use: rename... - uv_unlink(tempfile) -- ...and mark for garbage collection - - local err = uv_copyfile(compile_location, target_location) - a.schedule() - if err then - return logger:error('Error during parser installation: %s', err) + if i == #cmd_list + 1 then + finished_commands = finished_commands + 1 + return print(get_job_status() .. " " .. success_message) end -end ----@async ----@param logger Logger ----@param query_src string ----@param query_dir string ----@return string? err -local function do_link_queries(logger, query_src, query_dir) - uv_unlink(query_dir) - local err = uv_symlink(query_src, query_dir, { dir = true, junction = true }) - a.schedule() - if err then - return logger:error(err) + local attr = cmd_list[i] + if attr.info then + print(get_job_status() .. " " .. attr.info) end -end ----@async ----@param logger Logger ----@param query_src string ----@param query_dir string ----@return string? err -local function do_copy_queries(logger, query_src, query_dir) - rmpath(query_dir) - local err = uv_mkdir(query_dir, 493) -- tonumber('755', 8) - - for f in fs.dir(query_src) do - err = uv_copyfile(fs.joinpath(query_src, f), fs.joinpath(query_dir, f)) + if attr.opts and attr.opts.args and M.command_extra_args[attr.cmd] then + vim.list_extend(attr.opts.args, M.command_extra_args[attr.cmd]) end - a.schedule() - if err then - return logger:error(err) - end -end ----@async ----@param lang string ----@param cache_dir string ----@param install_dir string ----@param generate? boolean ----@return string? err -local function try_install_lang(lang, cache_dir, install_dir, generate) - local logger = log.new('install/' .. lang) - - local repo = get_parser_install_info(lang) - local project_name = 'tree-sitter-' .. lang - if repo then - local revision = repo.revision - - local compile_location ---@type string - if repo.path then - compile_location = fs.normalize(repo.path) + if type(attr.cmd) == "function" then + local ok, err = pcall(attr.cmd) + if ok then + M.iter_cmd(cmd_list, i + 1, lang, success_message) else - local project_dir = fs.joinpath(cache_dir, project_name) - rmpath(project_dir) - - revision = revision or repo.branch or 'main' - - local err = do_download(logger, repo.url, project_name, cache_dir, revision, project_dir) - if err then - return err - end - compile_location = fs.joinpath(cache_dir, project_name) + failed_commands = failed_commands + 1 + finished_commands = finished_commands + 1 + return api.nvim_err_writeln( + (attr.err or ("Failed to execute the following command:\n" .. vim.inspect(attr))) .. "\n" .. vim.inspect(err) + ) end - - if repo.location then - compile_location = fs.joinpath(compile_location, repo.location) - end - - do -- generate parser from grammar - if repo.generate or generate then - local err = do_generate(logger, repo, compile_location) - if err then - return err - end - end - end - - do -- compile parser - local err = do_compile(logger, compile_location) - if err then - return err - end - end - - do -- install parser - local parser_lib_name = fs.joinpath(compile_location, 'parser.so') - local install_location = fs.joinpath(install_dir, lang) .. '.so' - local err = do_install(logger, parser_lib_name, install_location) - if err then - return err - end - - local revfile = fs.joinpath(config.get_install_dir('parser-info') or '', lang .. '.revision') - util.write_file(revfile, revision or '') - end - end - - do -- install queries - local query_src = M.get_package_path('runtime', 'queries', lang) - local query_dir = fs.joinpath(config.get_install_dir('queries'), lang) - local task ---@type function - - if repo and repo.queries and repo.path then -- link queries from local repo - query_src = fs.joinpath(fs.normalize(repo.path), repo.queries) - task = do_link_queries - elseif repo and repo.queries then -- copy queries from tarball - query_src = fs.joinpath(cache_dir, project_name, repo.queries) - task = do_copy_queries - elseif uv.fs_stat(query_src) then -- link queries from runtime - task = do_link_queries - end - - if task then - local err = task(logger, query_src, query_dir) - if err then - return err - end - end - end - - -- clean up - if repo and not repo.path then - rmpath(fs.joinpath(cache_dir, project_name)) - a.schedule() - end - - logger:info('Language installed') -end - -local installing = {} ---@type table - ----@async ----@param lang string ----@param cache_dir string ----@param install_dir string ----@param force? boolean ----@param generate? boolean ----@return boolean success -local function install_lang(lang, cache_dir, install_dir, force, generate) - if not force and vim.list_contains(config.get_installed(), lang) then - return true - elseif installing[lang] then - local success = vim.wait(INSTALL_TIMEOUT, function() - return not installing[lang] - end) - return success else - installing[lang] = true - local err = try_install_lang(lang, cache_dir, install_dir, generate) - installing[lang] = nil - return not err - end -end - ---- Reload the parser table and user modifications in case of update -local function reload_parsers() - package.loaded['nvim-treesitter.parsers'] = nil - ---@diagnostic disable-next-line:duplicate-require - parsers = require('nvim-treesitter.parsers') - vim.api.nvim_exec_autocmds('User', { pattern = 'TSUpdate' }) -end - ----@class InstallOptions ----@field force? boolean ----@field generate? boolean ----@field max_jobs? integer ----@field summary? boolean - ---- Install a parser ----@async ----@param languages string[] ----@param options? InstallOptions ----@return boolean true if installation successful -local function install(languages, options) - options = options or {} - - local cache_dir = fs.normalize(fn.stdpath('cache') --[[@as string]]) - if not uv.fs_stat(cache_dir) then - fn.mkdir(cache_dir, 'p') - end - - local install_dir = config.get_install_dir('parser') - - local tasks = {} ---@type async.TaskFun[] - local done = 0 - for _, lang in ipairs(languages) do - tasks[#tasks + 1] = a.async(--[[@async]] function() - a.schedule() - local success = install_lang(lang, cache_dir, install_dir, options.force, options.generate) - if success then - done = done + 1 - end - end) - end - - join(options and options.max_jobs or MAX_JOBS, tasks) - if #tasks > 1 then - a.schedule() - if options and options.summary then - log.info('Installed %d/%d languages', done, #tasks) - end - end - return done == #tasks -end - ----@async ----@param languages string[]|string ----@param options? InstallOptions -M.install = a.async(function(languages, options) - reload_parsers() - languages = config.norm_languages(languages, { unsupported = true }) - return install(languages, options) -end) - ----@async ----@param languages? string[]|string ----@param options? InstallOptions -M.update = a.async(function(languages, options) - reload_parsers() - if not languages or #languages == 0 then - languages = 'all' - end - languages = config.norm_languages(languages, { missing = true, unsupported = true }) - languages = vim.tbl_filter(needs_update, languages) ---@type string[] - - local summary = options and options.summary - if #languages > 0 then - return install( - languages, - { force = true, summary = summary, max_jobs = options and options.max_jobs } - ) - else - if summary then - log.info('All parsers are up-to-date') - end - return true - end -end) - ----@async ----@param logger Logger ----@param lang string ----@param parser string ----@param queries string ----@return string? err -local function uninstall_lang(logger, lang, parser, queries) - logger:debug('Uninstalling ' .. lang) - - if fn.filereadable(parser) == 1 then - logger:debug('Unlinking ' .. parser) - local perr = uv_unlink(parser) - a.schedule() - if perr then - return logger:error(perr) - end - end - - local stat = uv.fs_lstat(queries) - if stat then - logger:debug('Unlinking ' .. queries) - local qerr ---@type string? - if stat.type == 'link' then - qerr = uv_unlink(queries) - else - qerr = rmpath(queries) - end - a.schedule() - if qerr then - return logger:error(qerr) - end - end - - logger:info('Language uninstalled') -end - ----@async ----@param languages string[]|string ----@param options? InstallOptions -M.uninstall = a.async(function(languages, options) - vim.api.nvim_exec_autocmds('User', { pattern = 'TSUpdate' }) - languages = config.norm_languages(languages or 'all', { missing = true, dependencies = true }) - - local parser_dir = config.get_install_dir('parser') - local query_dir = config.get_install_dir('queries') - local installed = config.get_installed() - - local tasks = {} ---@type async.TaskFun[] - local done = 0 - for _, lang in ipairs(languages) do - local logger = log.new('uninstall/' .. lang) - if not vim.list_contains(installed, lang) then - log.warn('Parser for ' .. lang .. ' is not managed by nvim-treesitter') - else - local parser = fs.joinpath(parser_dir, lang) .. '.so' - local queries = fs.joinpath(query_dir, lang) - tasks[#tasks + 1] = a.async(--[[@async]] function() - local err = uninstall_lang(logger, lang, parser, queries) - if not err then - done = done + 1 + local handle + local stdout = luv.new_pipe(false) + local stderr = luv.new_pipe(false) + attr.opts.stdio = { nil, stdout, stderr } + ---@type userdata + handle = luv.spawn( + attr.cmd, + attr.opts, + vim.schedule_wrap(function(code) + if code ~= 0 then + stdout:read_stop() + stderr:read_stop() end + stdout:close() + stderr:close() + handle:close() + if code ~= 0 then + failed_commands = failed_commands + 1 + finished_commands = finished_commands + 1 + if complete_std_output[handle] and complete_std_output[handle] ~= "" then + print(complete_std_output[handle]) + end + + local err_msg = complete_error_output[handle] or "" + api.nvim_err_writeln( + "nvim-treesitter[" + .. lang + .. "]: " + .. (attr.err or ("Failed to execute the following command:\n" .. vim.inspect(attr))) + .. "\n" + .. err_msg + ) + return + end + M.iter_cmd(cmd_list, i + 1, lang, success_message) end) + ) + luv.read_start(stdout, onread(handle, false)) + luv.read_start(stderr, onread(handle, true)) + end +end + +local function get_command(cmd) + local options = "" + if cmd.opts and cmd.opts.args then + if M.command_extra_args[cmd.cmd] then + vim.list_extend(cmd.opts.args, M.command_extra_args[cmd.cmd]) + end + for _, opt in ipairs(cmd.opts.args) do + options = string.format("%s %s", options, opt) end end - join(MAX_JOBS, tasks) - if #tasks > 1 then - a.schedule() - if options and options.summary then - log.info('Uninstalled %d/%d languages', done, #tasks) + local final = string.format("%s %s", cmd.cmd, options) + if cmd.opts and cmd.opts.cwd then + final = shell.make_directory_change_for_command(cmd.opts.cwd, final) + end + return final +end + +local function iter_cmd_sync(cmd_list) + for _, cmd in ipairs(cmd_list) do + if cmd.info then + print(cmd.info) + end + + if type(cmd.cmd) == "function" then + cmd.cmd() + else + local ret = vim.fn.system(get_command(cmd)) + if vim.v.shell_error ~= 0 then + print(ret) + api.nvim_err_writeln( + (cmd.err and cmd.err .. "\n" or "") .. "Failed to execute the following command:\n" .. vim.inspect(cmd) + ) + return false + end end end -end) + + return true +end + +---@param cache_folder string +---@param install_folder string +---@param lang string +---@param repo InstallInfo +---@param with_sync boolean +---@param generate_from_grammar boolean +local function run_install(cache_folder, install_folder, lang, repo, with_sync, generate_from_grammar) + parsers.reset_cache() + + local path_sep = utils.get_path_sep() + + local project_name = "tree-sitter-" .. lang + local maybe_local_path = vim.fn.expand(repo.url) + local from_local_path = vim.fn.isdirectory(maybe_local_path) == 1 + if from_local_path then + repo.url = maybe_local_path + end + + -- compile_location only needed for typescript installs. + local compile_location + if from_local_path then + compile_location = repo.url + else + local repo_location = project_name + if repo.location then + repo_location = repo_location .. "/" .. repo.location + end + repo_location = repo_location:gsub("/", path_sep) + compile_location = utils.join_path(cache_folder, repo_location) + end + local parser_lib_name = utils.join_path(install_folder, lang) .. ".so" + + generate_from_grammar = repo.requires_generate_from_grammar or generate_from_grammar + + if generate_from_grammar and vim.fn.executable "tree-sitter" ~= 1 then + api.nvim_err_writeln "tree-sitter CLI not found: `tree-sitter` is not executable!" + if repo.requires_generate_from_grammar then + api.nvim_err_writeln( + "tree-sitter CLI is needed because `" + .. lang + .. "` is marked that it needs " + .. "to be generated from the grammar definitions to be compatible with nvim!" + ) + end + return + else + if not M.ts_generate_args then + local ts_cli_version = utils.ts_cli_version() + if ts_cli_version and vim.split(ts_cli_version, " ")[1] > "0.20.2" then + M.ts_generate_args = { "generate", "--abi", vim.treesitter.language_version } + else + M.ts_generate_args = { "generate" } + end + end + end + if generate_from_grammar and vim.fn.executable "node" ~= 1 then + api.nvim_err_writeln "Node JS not found: `node` is not executable!" + return + end + local cc = shell.select_executable(M.compilers) + if not cc then + api.nvim_err_writeln('No C compiler found! "' .. table.concat( + vim.tbl_filter(function(c) + return type(c) == "string" + end, M.compilers), + '", "' + ) .. '" are not executable.') + return + end + local revision = configs.get_update_strategy() == "lockfile" and get_revision(lang) + + local command_list = {} + if not from_local_path then + vim.list_extend(command_list, { shell.select_install_rm_cmd(cache_folder, project_name) }) + vim.list_extend( + command_list, + shell.select_download_commands(repo, project_name, cache_folder, revision, M.prefer_git) + ) + end + if generate_from_grammar then + if repo.generate_requires_npm then + if vim.fn.executable "npm" ~= 1 then + api.nvim_err_writeln("`" .. lang .. "` requires NPM to be installed from grammar.js") + return + end + vim.list_extend(command_list, { + { + cmd = "npm", + info = "Installing NPM dependencies of " .. lang .. " parser", + err = "Error during `npm install` (required for parser generation of " .. lang .. " with npm dependencies)", + opts = { + args = { "install" }, + cwd = compile_location, + }, + }, + }) + end + vim.list_extend(command_list, { + { + cmd = vim.fn.exepath "tree-sitter", + info = "Generating source files from grammar.js...", + err = 'Error during "tree-sitter generate"', + opts = { + args = M.ts_generate_args, + cwd = compile_location, + }, + }, + }) + end + vim.list_extend(command_list, { + shell.select_compile_command(repo, cc, compile_location), + shell.select_mv_cmd("parser.so", parser_lib_name, compile_location), + { + cmd = function() + vim.fn.writefile({ revision or "" }, utils.join_path(configs.get_parser_info_dir(), lang .. ".revision")) + end, + }, + { -- auto-attach modules after installation + cmd = function() + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if parsers.get_buf_lang(buf) == lang then + for _, mod in ipairs(require("nvim-treesitter.configs").available_modules()) do + require("nvim-treesitter.configs").reattach_module(mod, buf) + end + end + end + end, + }, + }) + if not from_local_path then + vim.list_extend(command_list, { shell.select_install_rm_cmd(cache_folder, project_name) }) + end + + if with_sync then + if iter_cmd_sync(command_list) == true then + print("Treesitter parser for " .. lang .. " has been installed") + end + else + M.iter_cmd(command_list, 1, lang, "Treesitter parser for " .. lang .. " has been installed") + end +end + +---@param lang string +---@param ask_reinstall boolean +---@param cache_folder string +---@param install_folder string +---@param with_sync boolean +---@param generate_from_grammar boolean +local function install_lang(lang, ask_reinstall, cache_folder, install_folder, with_sync, generate_from_grammar) + if is_installed(lang) and ask_reinstall ~= "force" then + if not ask_reinstall then + return + end + + local yesno = fn.input(lang .. " parser already available: would you like to reinstall ? y/n: ") + print "\n " + if not string.match(yesno, "^y.*") then + return + end + end + + local ok, install_info = pcall(get_parser_install_info, lang, true) + if not ok then + vim.notify("Installation not possible: " .. install_info, vim.log.levels.ERROR) + if not parsers.get_parser_configs()[lang] then + vim.notify( + "See https://github.com/nvim-treesitter/nvim-treesitter/#adding-parsers on how to add a new parser!", + vim.log.levels.INFO + ) + end + return + end + + run_install(cache_folder, install_folder, lang, install_info, with_sync, generate_from_grammar) +end + +---@return function +local function install(options) + options = options or {} + local with_sync = options.with_sync + local ask_reinstall = options.ask_reinstall + local generate_from_grammar = options.generate_from_grammar + local exclude_configured_parsers = options.exclude_configured_parsers + + return function(...) + if fn.executable "git" == 0 then + return api.nvim_err_writeln "Git is required on your system to run this command" + end + + local cache_folder, err = utils.get_cache_dir() + if err then + return api.nvim_err_writeln(err) + end + assert(cache_folder) + + local install_folder + install_folder, err = configs.get_parser_install_dir() + if err then + return api.nvim_err_writeln(err) + end + assert(install_folder) + + local languages + local ask + if ... == "all" then + languages = parsers.available_parsers() + ask = false + else + languages = vim.tbl_flatten { ... } + ask = ask_reinstall + end + + if exclude_configured_parsers then + languages = utils.difference(languages, configs.get_ignored_parser_installs()) + end + + if #languages > 1 then + reset_progress_counter() + end + + for _, lang in ipairs(languages) do + install_lang(lang, ask, cache_folder, install_folder, with_sync, generate_from_grammar) + end + end +end + +function M.setup_auto_install() + vim.api.nvim_create_autocmd("FileType", { + pattern = { "*" }, + callback = function() + local lang = parsers.get_buf_lang() + if parsers.get_parser_configs()[lang] and not is_installed(lang) and not is_ignored_parser(lang) then + install() { lang } + end + end, + }) +end + +function M.update(options) + options = options or {} + return function(...) + M.lockfile = {} + reset_progress_counter() + if ... and ... ~= "all" then + local languages = vim.tbl_flatten { ... } + local installed = 0 + for _, lang in ipairs(languages) do + if (not is_installed(lang)) or (needs_update(lang)) then + installed = installed + 1 + install { + ask_reinstall = "force", + with_sync = options.with_sync, + }(lang) + end + end + if installed == 0 then + utils.notify "Parsers are up-to-date!" + end + else + local parsers_to_update = configs.get_update_strategy() == "lockfile" and outdated_parsers() + or info.installed_parsers() + if #parsers_to_update == 0 then + utils.notify "All parsers are up-to-date!" + end + for _, lang in pairs(parsers_to_update) do + install { + ask_reinstall = "force", + exclude_configured_parsers = true, + with_sync = options.with_sync, + }(lang) + end + end + end +end + +function M.uninstall(...) + if vim.tbl_contains({ "all" }, ...) then + reset_progress_counter() + local installed = info.installed_parsers() + for _, langitem in pairs(installed) do + M.uninstall(langitem) + end + elseif ... then + local ensure_installed_parsers = configs.get_ensure_installed_parsers() + if ensure_installed_parsers == "all" then + ensure_installed_parsers = parsers.available_parsers() + end + ensure_installed_parsers = utils.difference(ensure_installed_parsers, configs.get_ignored_parser_installs()) + + local languages = vim.tbl_flatten { ... } + for _, lang in ipairs(languages) do + local install_dir, err = configs.get_parser_install_dir() + if err then + return api.nvim_err_writeln(err) + end + + if vim.tbl_contains(ensure_installed_parsers, lang) then + vim.notify( + "Uninstalling " + .. lang + .. '. But the parser is still configured in "ensure_installed" setting of nvim-treesitter.' + .. " Please consider updating your config!", + vim.log.levels.ERROR + ) + end + + local parser_lib = utils.join_path(install_dir, lang) .. ".so" + local all_parsers = vim.api.nvim_get_runtime_file("parser/" .. lang .. ".so", true) + if vim.fn.filereadable(parser_lib) == 1 then + local command_list = { + shell.select_rm_file_cmd(parser_lib, "Uninstalling parser for " .. lang), + { + cmd = function() + local all_parsers_after_deletion = vim.api.nvim_get_runtime_file("parser/" .. lang .. ".so", true) + if #all_parsers_after_deletion > 0 then + vim.notify( + "Tried to uninstall parser for " + .. lang + .. "! But the parser is still installed (not by nvim-treesitter)." + .. " Please delete the following files manually: " + .. table.concat(all_parsers_after_deletion, ", "), + vim.log.levels.ERROR + ) + end + end, + }, + } + M.iter_cmd(command_list, 1, lang, "Treesitter parser for " .. lang .. " has been uninstalled") + elseif #all_parsers > 0 then + vim.notify( + "Parser for " + .. lang + .. " is installed! But not by nvim-treesitter! Please manually remove the following files: " + .. table.concat(all_parsers, ", "), + vim.log.levels.ERROR + ) + end + end + end +end + +function M.write_lockfile(verbose, skip_langs) + local sorted_parsers = {} + -- Load previous lockfile + load_lockfile() + skip_langs = skip_langs or {} + + for k, v in pairs(parsers.get_parser_configs()) do + table.insert(sorted_parsers, { name = k, parser = v }) + end + + table.sort(sorted_parsers, function(a, b) + return a.name < b.name + end) + + for _, v in ipairs(sorted_parsers) do + if not vim.tbl_contains(skip_langs, v.name) then + -- I'm sure this can be done in aync way with iter_cmd + local sha + if v.parser.install_info.branch then + sha = vim.split( + vim.fn.systemlist( + "git ls-remote " .. v.parser.install_info.url .. " | grep refs/heads/" .. v.parser.install_info.branch + )[1], + "\t" + )[1] + else + sha = vim.split(vim.fn.systemlist("git ls-remote " .. v.parser.install_info.url)[1], "\t")[1] + end + lockfile[v.name] = { revision = sha } + if verbose then + print(v.name .. ": " .. sha) + end + else + print("Skipping " .. v.name) + end + end + + if verbose then + print(vim.inspect(lockfile)) + end + vim.fn.writefile( + vim.fn.split(vim.fn.json_encode(lockfile), "\n"), + utils.join_path(utils.get_package_path(), "lockfile.json") + ) +end + +M.ensure_installed = install { exclude_configured_parsers = true } +M.ensure_installed_sync = install { with_sync = true, exclude_configured_parsers = true } + +M.commands = { + TSInstall = { + run = install { ask_reinstall = true }, + ["run!"] = install { ask_reinstall = "force" }, + args = { + "-nargs=+", + "-bang", + "-complete=custom,nvim_treesitter#installable_parsers", + }, + }, + TSInstallFromGrammar = { + run = install { generate_from_grammar = true, ask_reinstall = true }, + ["run!"] = install { generate_from_grammar = true, ask_reinstall = "force" }, + args = { + "-nargs=+", + "-bang", + "-complete=custom,nvim_treesitter#installable_parsers", + }, + }, + TSInstallSync = { + run = install { with_sync = true, ask_reinstall = true }, + ["run!"] = install { with_sync = true, ask_reinstall = "force" }, + args = { + "-nargs=+", + "-bang", + "-complete=custom,nvim_treesitter#installable_parsers", + }, + }, + TSUpdate = { + run = M.update {}, + args = { + "-nargs=*", + "-complete=custom,nvim_treesitter#installed_parsers", + }, + }, + TSUpdateSync = { + run = M.update { with_sync = true }, + args = { + "-nargs=*", + "-complete=custom,nvim_treesitter#installed_parsers", + }, + }, + TSUninstall = { + run = M.uninstall, + args = { + "-nargs=+", + "-complete=custom,nvim_treesitter#installed_parsers", + }, + }, +} return M diff --git a/lua/nvim-treesitter/locals.lua b/lua/nvim-treesitter/locals.lua new file mode 100644 index 000000000..dcfba2683 --- /dev/null +++ b/lua/nvim-treesitter/locals.lua @@ -0,0 +1,350 @@ +-- Functions to handle locals +-- Locals are a generalization of definition and scopes +-- its the way nvim-treesitter uses to "understand" the code + +local queries = require "nvim-treesitter.query" +local ts_utils = require "nvim-treesitter.ts_utils" +local ts_query = vim.treesitter.query +local api = vim.api + +local M = {} + +function M.collect_locals(bufnr) + return queries.collect_group_results(bufnr, "locals") +end + +-- Iterates matches from a locals query file. +-- @param bufnr the buffer +-- @param root the root node +function M.iter_locals(bufnr, root) + return queries.iter_group_results(bufnr, "locals", root) +end + +function M.get_locals(bufnr) + return queries.get_matches(bufnr, "locals") +end + +--- Creates unique id for a node based on text and range +-- @param scope: the scope node of the definition +-- @param bufnr: the buffer +-- @param node_text: the node text to use +-- @returns a string id +function M.get_definition_id(scope, node_text) + -- Add a valid starting character in case node text doesn't start with a valid one. + return table.concat({ "k", node_text or "", scope:range() }, "_") +end + +function M.get_definitions(bufnr) + local locals = M.get_locals(bufnr) + + local defs = {} + + for _, loc in ipairs(locals) do + if loc.definition then + table.insert(defs, loc.definition) + end + end + + return defs +end + +function M.get_scopes(bufnr) + local locals = M.get_locals(bufnr) + + local scopes = {} + + for _, loc in ipairs(locals) do + if loc.scope and loc.scope.node then + table.insert(scopes, loc.scope.node) + end + end + + return scopes +end + +function M.get_references(bufnr) + local locals = M.get_locals(bufnr) + + local refs = {} + + for _, loc in ipairs(locals) do + if loc.reference and loc.reference.node then + table.insert(refs, loc.reference.node) + end + end + + return refs +end + +--- Gets a table with all the scopes containing a node +-- The order is from most specific to least (bottom up) +function M.get_scope_tree(node, bufnr) + local scopes = {} + + for scope in M.iter_scope_tree(node, bufnr) do + table.insert(scopes, scope) + end + + return scopes +end + +--- Iterates over a nodes scopes moving from the bottom up +function M.iter_scope_tree(node, bufnr) + local last_node = node + return function() + if not last_node then + return + end + + local scope = M.containing_scope(last_node, bufnr, false) or ts_utils.get_root_for_node(node) + + last_node = scope:parent() + + return scope + end +end + +-- Gets a table of all nodes and their 'kinds' from a locals list +-- @param local_def the local list result +-- @returns a list of node entries +function M.get_local_nodes(local_def) + local result = {} + + M.recurse_local_nodes(local_def, function(def, node, kind) + table.insert(result, vim.tbl_extend("keep", { kind = kind }, def)) + end) + + return result +end + +-- Recurse locals results until a node is found. +-- The accumulator function is given +-- * The table of the node +-- * The node +-- * The full definition match `@definition.var.something` -> 'var.something' +-- * The last definition match `@definition.var.something` -> 'something' +-- @param The locals result +-- @param The accumulator function +-- @param The full match path to append to +-- @param The last match +function M.recurse_local_nodes(local_def, accumulator, full_match, last_match) + if type(local_def) ~= "table" then + return + end + + if local_def.node then + accumulator(local_def, local_def.node, full_match, last_match) + else + for match_key, def in pairs(local_def) do + M.recurse_local_nodes(def, accumulator, full_match and (full_match .. "." .. match_key) or match_key, match_key) + end + end +end + +--- Get a single dimension table to look definition nodes. +-- Keys are generated by using the range of the containing scope and the text of the definition node. +-- This makes looking up a definition for a given scope a simple key lookup. +-- +-- This is memoized by buffer tick. If the function is called in succession +-- without the buffer tick changing, then the previous result will be used +-- since the syntax tree hasn't changed. +-- +-- Usage lookups require finding the definition of the node, so `find_definition` +-- is called very frequently, which is why this lookup must be fast as possible. +-- +-- @param bufnr: the buffer +-- @returns a table for looking up definitions +M.get_definitions_lookup_table = ts_utils.memoize_by_buf_tick(function(bufnr) + local definitions = M.get_definitions(bufnr) + local result = {} + + for _, definition in ipairs(definitions) do + for _, node_entry in ipairs(M.get_local_nodes(definition)) do + local scopes = M.get_definition_scopes(node_entry.node, bufnr, node_entry.scope) + -- Always use the highest valid scope + local scope = scopes[#scopes] + local node_text = ts_query.get_node_text(node_entry.node, bufnr) + local id = M.get_definition_id(scope, node_text) + + result[id] = node_entry + end + end + + return result +end) + +--- Gets all the scopes of a definition based on the scope type +-- Scope types can be +-- +-- "parent": Uses the parent of the containing scope, basically, skipping a scope +-- "global": Uses the top most scope +-- "local": Uses the containing scope of the definition. This is the default +-- +-- @param node: the definition node +-- @param bufnr: the buffer +-- @param scope_type: the scope type +function M.get_definition_scopes(node, bufnr, scope_type) + local scopes = {} + local scope_count = 1 + + -- Definition is valid for the containing scope + -- and the containing scope of that scope + if scope_type == "parent" then + scope_count = 2 + -- Definition is valid in all parent scopes + elseif scope_type == "global" then + scope_count = nil + end + + local i = 0 + for scope in M.iter_scope_tree(node, bufnr) do + table.insert(scopes, scope) + i = i + 1 + + if scope_count and i >= scope_count then + break + end + end + + return scopes +end + +function M.find_definition(node, bufnr) + local def_lookup = M.get_definitions_lookup_table(bufnr) + local node_text = ts_query.get_node_text(node, bufnr) + + for scope in M.iter_scope_tree(node, bufnr) do + local id = M.get_definition_id(scope, node_text) + + if def_lookup[id] then + local entry = def_lookup[id] + + return entry.node, scope, entry.kind + end + end + + return node, ts_utils.get_root_for_node(node), nil +end + +-- Finds usages of a node in a given scope. +-- @param node the node to find usages for +-- @param scope_node the node to look within +-- @returns a list of nodes +function M.find_usages(node, scope_node, bufnr) + local bufnr = bufnr or api.nvim_get_current_buf() + local node_text = ts_query.get_node_text(node, bufnr) + + if not node_text or #node_text < 1 then + return {} + end + + local scope_node = scope_node or ts_utils.get_root_for_node(node) + local usages = {} + + for match in M.iter_locals(bufnr, scope_node) do + if + match.reference + and match.reference.node + and ts_query.get_node_text(match.reference.node, bufnr) == node_text + then + local def_node, _, kind = M.find_definition(match.reference.node, bufnr) + + if kind == nil or def_node == node then + table.insert(usages, match.reference.node) + end + end + end + + return usages +end + +function M.containing_scope(node, bufnr, allow_scope) + local bufnr = bufnr or api.nvim_get_current_buf() + local allow_scope = allow_scope == nil or allow_scope == true + + local scopes = M.get_scopes(bufnr) + if not node or not scopes then + return + end + + local iter_node = node + + while iter_node ~= nil and not vim.tbl_contains(scopes, iter_node) do + iter_node = iter_node:parent() + end + + return iter_node or (allow_scope and node or nil) +end + +function M.nested_scope(node, cursor_pos) + local bufnr = api.nvim_get_current_buf() + + local scopes = M.get_scopes(bufnr) + if not node or not scopes then + return + end + + local row = cursor_pos.row + local col = cursor_pos.col + local scope = M.containing_scope(node) + + for _, child in ipairs(ts_utils.get_named_children(scope)) do + local row_, col_ = child:start() + if vim.tbl_contains(scopes, child) and ((row_ + 1 == row and col_ > col) or row_ + 1 > row) then + return child + end + end +end + +function M.next_scope(node) + local bufnr = api.nvim_get_current_buf() + + local scopes = M.get_scopes(bufnr) + if not node or not scopes then + return + end + + local scope = M.containing_scope(node) + + local parent = scope:parent() + if not parent then + return + end + + local is_prev = true + for _, child in ipairs(ts_utils.get_named_children(parent)) do + if child == scope then + is_prev = false + elseif not is_prev and vim.tbl_contains(scopes, child) then + return child + end + end +end + +function M.previous_scope(node) + local bufnr = api.nvim_get_current_buf() + + local scopes = M.get_scopes(bufnr) + if not node or not scopes then + return + end + + local scope = M.containing_scope(node) + + local parent = scope:parent() + if not parent then + return + end + + local is_prev = true + local children = ts_utils.get_named_children(parent) + for i = #children, 1, -1 do + if children[i] == scope then + is_prev = false + elseif not is_prev and vim.tbl_contains(scopes, children[i]) then + return children[i] + end + end +end + +return M diff --git a/lua/nvim-treesitter/log.lua b/lua/nvim-treesitter/log.lua deleted file mode 100644 index faf131094..000000000 --- a/lua/nvim-treesitter/log.lua +++ /dev/null @@ -1,100 +0,0 @@ -local echo = vim.api.nvim_echo - --- TODO(lewis6991): write these out to a file -local messages = {} --- @type {[1]: string, [2]: string?, [3]: string}[] - -local sev_to_hl = { - trace = 'DiagnosticHint', - debug = 'Normal', - info = 'MoreMsg', - warn = 'WarningMsg', - error = 'ErrorMsg', -} - ----@param ctx string? ----@return string -local function mkpfx(ctx) - return ctx and string.format('[nvim-treesitter/%s]', ctx) or '[nvim-treesitter]' -end - ----@class TSLogModule ----@field trace fun(fmt: string, ...: any) ----@field debug fun(fmt: string, ...: any) ----@field info fun(fmt: string, ...: any) ----@field warn fun(fmt: string, ...: any) ----@field error fun(fmt: string, ...: any) -local M = {} - ----@class Logger ----@field ctx? string -local Logger = {} - -M.Logger = Logger - ----@param ctx? string ----@return Logger -function M.new(ctx) - return setmetatable({ ctx = ctx }, { __index = Logger }) -end - ----@param m string ----@param ... any -function Logger:trace(m, ...) - messages[#messages + 1] = { 'trace', self.ctx, m:format(...) } -end - ----@param m string ----@param ... any -function Logger:debug(m, ...) - messages[#messages + 1] = { 'debug', self.ctx, m:format(...) } -end - ----@param m string ----@param ... any -function Logger:info(m, ...) - local m1 = m:format(...) - messages[#messages + 1] = { 'info', self.ctx, m1 } - echo({ { mkpfx(self.ctx) .. ': ' .. m1, sev_to_hl.info } }, true, {}) -end - ----@param m string ----@param ... any -function Logger:warn(m, ...) - local m1 = m:format(...) - messages[#messages + 1] = { 'warn', self.ctx, m1 } - echo({ { mkpfx(self.ctx) .. ' warning: ' .. m1, sev_to_hl.warn } }, true, {}) -end - ----@param m string ----@param ... any ----@return string -function Logger:error(m, ...) - local m1 = m:format(...) - messages[#messages + 1] = { 'error', self.ctx, m1 } - echo({ { mkpfx(self.ctx) .. ' error: ' .. m1, sev_to_hl.error } }, true, {}) - return m1 -end - -local noctx_logger = M.new() - -setmetatable(M, { - __index = function(t, k) - --- @diagnostic disable-next-line:no-unknown - t[k] = function(...) - return noctx_logger[k](noctx_logger, ...) - end - return t[k] - end, -}) - -function M.show() - for _, l in ipairs(messages) do - local sev, ctx, msg = l[1], l[2], l[3] - local hl = sev_to_hl[sev] - local text = ctx and string.format('%s(%s): %s', sev, ctx, msg) - or string.format('%s: %s', sev, msg) - echo({ { text, hl } }, false, {}) - end -end - -return M diff --git a/lua/nvim-treesitter/parsers.lua b/lua/nvim-treesitter/parsers.lua index 8c9ff4a18..0246cde81 100644 --- a/lua/nvim-treesitter/parsers.lua +++ b/lua/nvim-treesitter/parsers.lua @@ -1,2703 +1,1426 @@ ----@type nvim-ts.parsers -return { - ada = { - install_info = { - revision = '6b58259a08b1a22ba0247a7ce30be384db618da6', - url = 'https://github.com/briot/tree-sitter-ada', - }, - maintainers = { '@briot' }, - tier = 2, - }, - agda = { - install_info = { - revision = 'e8d47a6987effe34d5595baf321d82d3519a8527', - url = 'https://github.com/tree-sitter/tree-sitter-agda', - }, - maintainers = { '@Decodetalkers' }, - tier = 2, - }, - angular = { - install_info = { - revision = 'f0d0685701b70883fa2dfe94ee7dc27965cab841', - url = 'https://github.com/dlvandenberg/tree-sitter-angular', - }, - maintainers = { '@dlvandenberg' }, - requires = { 'html', 'html_tags' }, - tier = 2, - }, - apex = { - install_info = { - location = 'apex', - revision = '3597575a429766dd7ecce9f5bb97f6fec4419d5d', - url = 'https://github.com/aheber/tree-sitter-sfapex', - }, - maintainers = { '@aheber', '@xixiafinland' }, - tier = 2, - }, - arduino = { - install_info = { - revision = '11dd46c9ae25135c473c0003a133bb06a484af0c', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-arduino', - }, - maintainers = { '@ObserverOfTime' }, - requires = { 'cpp' }, - tier = 2, - }, - asm = { - install_info = { - revision = '839741fef4dab5128952334624905c82b40c7133', - url = 'https://github.com/RubixDev/tree-sitter-asm', - }, - maintainers = { '@RubixDev' }, - tier = 2, - }, - astro = { - install_info = { - revision = '213f6e6973d9b456c6e50e86f19f66877e7ef0ee', - url = 'https://github.com/virchau13/tree-sitter-astro', - }, - maintainers = { '@virchau13' }, - requires = { 'html', 'html_tags' }, - tier = 2, - }, - authzed = { - install_info = { - revision = '83e5c26a8687eb4688fe91d690c735cc3d21ad81', - url = 'https://github.com/mleonidas/tree-sitter-authzed', - }, - maintainers = { '@mattpolzin' }, - tier = 2, - }, - awk = { - install_info = { - revision = '34bbdc7cce8e803096f47b625979e34c1be38127', - url = 'https://github.com/Beaglefoot/tree-sitter-awk', - }, - tier = 2, - }, - bash = { - install_info = { - revision = 'a06c2e4415e9bc0346c6b86d401879ffb44058f7', - url = 'https://github.com/tree-sitter/tree-sitter-bash', - }, - maintainers = { '@TravonteD' }, - tier = 2, - }, - bass = { - install_info = { - revision = '28dc7059722be090d04cd751aed915b2fee2f89a', - url = 'https://github.com/vito/tree-sitter-bass', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - beancount = { - install_info = { - revision = '429cff869513cf9e34a2cf604fbfaaedc467e809', - url = 'https://github.com/polarmutex/tree-sitter-beancount', - }, - maintainers = { '@polarmutex' }, - tier = 2, - }, - bibtex = { - install_info = { - revision = '8d04ed27b3bc7929f14b7df9236797dab9f3fa66', - url = 'https://github.com/latex-lsp/tree-sitter-bibtex', - }, - maintainers = { '@theHamsta', '@clason' }, - tier = 2, - }, - bicep = { - install_info = { - revision = 'bff59884307c0ab009bd5e81afd9324b46a6c0f9', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-bicep', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - bitbake = { - install_info = { - revision = 'a5d04fdb5a69a02b8fa8eb5525a60dfb5309b73b', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-bitbake', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - blade = { - install_info = { - revision = 'b9436b7b936907aff730de0dac1b99d7c632cc86', - url = 'https://github.com/EmranMR/tree-sitter-blade', - }, - maintainers = { '@calebdw' }, - tier = 2, - }, - bp = { - install_info = { - revision = 'ee641d15390183d7535777947ce0f2f1fbcee69f', - url = 'https://github.com/ambroisie/tree-sitter-bp', - }, - maintainers = { '@ambroisie' }, - readme_note = 'Android Blueprint', - tier = 2, - }, - bpftrace = { - install_info = { - revision = '774f4458ad39691336ead1ee361b22434c4cdec7', - url = 'https://github.com/sgruszka/tree-sitter-bpftrace', - }, - maintainers = { '@sgruszka' }, - tier = 2, - }, - brightscript = { - install_info = { - revision = '253fdfaa23814cb46c2d5fc19049fa0f2f62c6da', - url = 'https://github.com/ajdelcimmuto/tree-sitter-brightscript', - }, - maintainers = { '@ajdelcimmuto' }, - tier = 2, - }, - c = { - install_info = { - revision = 'ae19b676b13bdcc13b7665397e6d9b14975473dd', - url = 'https://github.com/tree-sitter/tree-sitter-c', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - c3 = { - install_info = { - revision = '78e2ae9cff29ef8ca6666006abe80f1236d42996', - url = 'https://github.com/c3lang/tree-sitter-c3', - }, - maintainers = { '@cbuttner' }, - tier = 2, - }, - c_sharp = { - install_info = { - revision = '88366631d598ce6595ec655ce1591b315cffb14c', - url = 'https://github.com/tree-sitter/tree-sitter-c-sharp', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - caddy = { - install_info = { - revision = '2686186edb61be47960431c93a204fb249681360', - url = 'https://github.com/opa-oz/tree-sitter-caddy', - }, - tier = 3, - }, - cairo = { - install_info = { - revision = '6238f609bea233040fe927858156dee5515a0745', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-cairo', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - capnp = { - install_info = { - revision = '7b0883c03e5edd34ef7bcf703194204299d7099f', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-capnp', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - chatito = { - install_info = { - revision = 'c0ed82c665b732395073f635c74c300f09530a7f', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-chatito', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - circom = { - install_info = { - revision = '02150524228b1e6afef96949f2d6b7cc0aaf999e', - url = 'https://github.com/Decurity/tree-sitter-circom', - }, - maintainers = { '@alexandr-martirosyan' }, - tier = 2, - }, - clojure = { - install_info = { - revision = 'e43eff80d17cf34852dcd92ca5e6986d23a7040f', - url = 'https://github.com/sogaiu/tree-sitter-clojure', - }, - maintainers = { '@NoahTheDuke' }, - tier = 2, - }, - cmake = { - install_info = { - revision = 'c7b2a71e7f8ecb167fad4c97227c838439280175', - url = 'https://github.com/uyha/tree-sitter-cmake', - }, - maintainers = { '@uyha' }, - tier = 2, - }, - comment = { - install_info = { - revision = '66272d2b6c73fb61157541b69dd0a7ce7b42a5ad', - url = 'https://github.com/stsewd/tree-sitter-comment', - }, - maintainers = { '@stsewd' }, - tier = 2, - }, - commonlisp = { - install_info = { - revision = '32323509b3d9fe96607d151c2da2c9009eb13a2f', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-commonlisp', - }, - maintainers = { '@theHamsta' }, - tier = 2, - }, - cooklang = { - install_info = { - revision = '4ebe237c1cf64cf3826fc249e9ec0988fe07e58e', - url = 'https://github.com/addcninblue/tree-sitter-cooklang', - }, - maintainers = { '@addcninblue' }, - tier = 2, - }, - corn = { - install_info = { - revision = '464654742cbfd3a3de560aba120998f1d5dfa844', - url = 'https://github.com/jakestanger/tree-sitter-corn', - }, - maintainers = { '@jakestanger' }, - tier = 2, - }, - cpon = { - install_info = { - revision = '594289eadfec719198e560f9d7fd243c4db678d5', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-cpon', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - cpp = { - install_info = { - revision = '8b5b49eb196bec7040441bee33b2c9a4838d6967', - url = 'https://github.com/tree-sitter/tree-sitter-cpp', - }, - maintainers = { '@theHamsta' }, - requires = { 'c' }, - tier = 2, - }, - css = { - install_info = { - revision = 'dda5cfc5722c429eaba1c910ca32c2c0c5bb1a3f', - url = 'https://github.com/tree-sitter/tree-sitter-css', - }, - maintainers = { '@TravonteD' }, - tier = 2, - }, - csv = { - install_info = { - location = 'csv', - revision = 'f6bf6e35eb0b95fbadea4bb39cb9709507fcb181', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-csv', - }, - maintainers = { '@amaanq' }, - requires = { 'tsv' }, - tier = 2, - }, - cuda = { - install_info = { - revision = '48b066f334f4cf2174e05a50218ce2ed98b6fd01', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-cuda', - }, - maintainers = { '@theHamsta' }, - requires = { 'cpp' }, - tier = 2, - }, - cue = { - install_info = { - revision = '20bb9195dac00b64c00ee494812abf3bf76f4181', - url = 'https://github.com/eonpatapon/tree-sitter-cue', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - cylc = { - install_info = { - revision = '6d1d81137112299324b526477ce1db989ab58fb8', - url = 'https://github.com/elliotfontaine/tree-sitter-cylc', - }, - maintainers = { '@elliotfontaine' }, - tier = 2, - }, - d = { - install_info = { - revision = 'fb028c8f14f4188286c2eef143f105def6fbf24f', - url = 'https://github.com/gdamore/tree-sitter-d', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - dart = { - install_info = { - revision = '0fc19c3a57b1109802af41d2b8f60d8835c5da3a', - url = 'https://github.com/UserNobody14/tree-sitter-dart', - }, - maintainers = { '@akinsho' }, - tier = 2, - }, - desktop = { - install_info = { - revision = 'v1.1.1', - url = 'https://github.com/ValdezFOmar/tree-sitter-desktop', - }, - maintainers = { '@ValdezFOmar' }, - tier = 1, - }, - devicetree = { - install_info = { - revision = 'e685f1f6ac1702b046415efb476444167d63e41a', - url = 'https://github.com/joelspadin/tree-sitter-devicetree', - }, - maintainers = { '@jedrzejboczar' }, - tier = 2, - }, - dhall = { - install_info = { - revision = '62013259b26ac210d5de1abf64cf1b047ef88000', - url = 'https://github.com/jbellerb/tree-sitter-dhall', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - diff = { - install_info = { - revision = '2520c3f934b3179bb540d23e0ef45f75304b5fed', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-diff', - }, - maintainers = { '@gbprod' }, - tier = 2, - }, - disassembly = { - install_info = { - revision = '0229c0211dba909c5d45129ac784a3f4d49c243a', - url = 'https://github.com/ColinKennedy/tree-sitter-disassembly', - }, - maintainers = { '@ColinKennedy' }, - tier = 2, - }, - djot = { - install_info = { - revision = '74fac1f53c6d52aeac104b6874e5506be6d0cfe6', - url = 'https://github.com/treeman/tree-sitter-djot', - }, - maintainers = { '@NoahTheDuke' }, - tier = 2, - }, - dockerfile = { - install_info = { - revision = '971acdd908568b4531b0ba28a445bf0bb720aba5', - url = 'https://github.com/camdencheek/tree-sitter-dockerfile', - }, - maintainers = { '@camdencheek' }, - tier = 2, - }, - dot = { - install_info = { - revision = '80327abbba6f47530edeb0df9f11bd5d5c93c14d', - url = 'https://github.com/rydesun/tree-sitter-dot', - }, - maintainers = { '@rydesun' }, - tier = 2, - }, - doxygen = { - install_info = { - revision = 'ccd998f378c3f9345ea4eeb223f56d7b84d16687', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-doxygen', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - dtd = { - install_info = { - location = 'dtd', - revision = '5000ae8f22d11fbe93939b05c1e37cf21117162d', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-xml', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - earthfile = { - install_info = { - revision = '5baef88717ad0156fd29a8b12d0d8245bb1096a8', - url = 'https://github.com/glehmann/tree-sitter-earthfile', - }, - maintainers = { '@glehmann' }, - tier = 2, - }, - ebnf = { - install_info = { - location = 'crates/tree-sitter-ebnf', - revision = '8e635b0b723c620774dfb8abf382a7f531894b40', - url = 'https://github.com/RubixDev/ebnf', - }, - maintainers = { '@RubixDev' }, - tier = 2, - }, - ecma = { - maintainers = { '@steelsojka' }, - readme_note = 'queries required by javascript, typescript, tsx, qmljs', - tier = 2, - }, - editorconfig = { - install_info = { - revision = 'v2.0.0', - url = 'https://github.com/ValdezFOmar/tree-sitter-editorconfig', - }, - maintainers = { '@ValdezFOmar' }, - tier = 1, - }, - eds = { - install_info = { - revision = '26d529e6cfecde391a03c21d1474eb51e0285805', - url = 'https://github.com/uyha/tree-sitter-eds', - }, - maintainers = { '@uyha' }, - tier = 2, - }, - eex = { - install_info = { - revision = 'f742f2fe327463335e8671a87c0b9b396905d1d1', - url = 'https://github.com/connorlay/tree-sitter-eex', - }, - maintainers = { '@connorlay' }, - tier = 2, - }, - elixir = { - install_info = { - revision = '7937d3b4d65fa574163cfa59394515d3c1cf16f4', - url = 'https://github.com/elixir-lang/tree-sitter-elixir', - }, - maintainers = { '@connorlay' }, - tier = 2, - }, - elm = { - install_info = { - revision = '6d9511c28181db66daee4e883f811f6251220943', - url = 'https://github.com/elm-tooling/tree-sitter-elm', - }, - maintainers = { '@zweimach' }, - tier = 2, - }, - elsa = { - install_info = { - revision = '0a66b2b3f3c1915e67ad2ef9f7dbd2a84820d9d7', - url = 'https://github.com/glapa-grossklag/tree-sitter-elsa', - }, - maintainers = { '@glapa-grossklag', '@amaanq' }, - tier = 2, - }, - elvish = { - install_info = { - revision = '5e7210d945425b77f82cbaebc5af4dd3e1ad40f5', - url = 'https://github.com/elves/tree-sitter-elvish', - }, - maintainers = { '@elves' }, - tier = 2, - }, - embedded_template = { - install_info = { - revision = '3499d85f0a0d937c507a4a65368f2f63772786e1', - url = 'https://github.com/tree-sitter/tree-sitter-embedded-template', - }, - tier = 2, - }, - enforce = { - install_info = { - revision = 'eb2796871d966264cdb041b797416ef1757c8b4f', - url = 'https://github.com/simonvic/tree-sitter-enforce', - }, - maintainers = { '@simonvic' }, - tier = 2, - }, - erlang = { - install_info = { - revision = '1d78195c4fbb1fc027eb3e4220427f1eb8bfc89e', - url = 'https://github.com/WhatsApp/tree-sitter-erlang', - }, - maintainers = { '@filmor' }, - tier = 2, - }, - facility = { - install_info = { - revision = 'e4bfd3e960de9f4b4648acb1c92e9b95b47d8cfb', - url = 'https://github.com/FacilityApi/tree-sitter-facility', - }, - maintainers = { '@bryankenote' }, - tier = 2, - }, - faust = { - install_info = { - revision = '122dd101919289ea809bad643712fcb483a1bed0', - url = 'https://github.com/khiner/tree-sitter-faust', - }, - maintainers = { '@khiner' }, - tier = 2, - }, - fennel = { - install_info = { - revision = '3f0f6b24d599e92460b969aabc4f4c5a914d15a0', - url = 'https://github.com/alexmozaidze/tree-sitter-fennel', - }, - maintainers = { '@alexmozaidze' }, - tier = 2, - }, - fidl = { - install_info = { - revision = '0a8910f293268e27ff554357c229ba172b0eaed2', - url = 'https://github.com/google/tree-sitter-fidl', - }, - maintainers = { '@chaopeng' }, - tier = 2, - }, - firrtl = { - install_info = { - revision = '8503d3a0fe0f9e427863cb0055699ff2d29ae5f5', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-firrtl', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - fish = { - install_info = { - revision = 'fa2143f5d66a9eb6c007ba9173525ea7aaafe788', - url = 'https://github.com/ram02z/tree-sitter-fish', - }, - maintainers = { '@ram02z' }, - tier = 2, - }, - foam = { - install_info = { - revision = '472c24f11a547820327fb1be565bcfff98ea96a4', - url = 'https://github.com/FoamScience/tree-sitter-foam', - }, - maintainers = { '@FoamScience' }, - tier = 2, - }, - forth = { - install_info = { - revision = '360ef13f8c609ec6d2e80782af69958b84e36cd0', - url = 'https://github.com/AlexanderBrevig/tree-sitter-forth', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - fortran = { - install_info = { - revision = 'be30d90dc7dfa4080b9c4abed3f400c9163a88df', - url = 'https://github.com/stadelmanma/tree-sitter-fortran', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - fsh = { - install_info = { - revision = 'fad2e175099a45efbc98f000cc196d3674cc45e0', - url = 'https://github.com/mgramigna/tree-sitter-fsh', - }, - maintainers = { '@mgramigna' }, - tier = 2, - }, - fsharp = { - install_info = { - location = 'fsharp', - revision = '1c2d9351d1f731c08cfdc4ed41e63126ae56e462', - url = 'https://github.com/ionide/tree-sitter-fsharp', - }, - maintainers = { '@nsidorenco' }, - tier = 2, - }, - func = { - install_info = { - revision = 'f780ca55e65e7d7360d0229331763e16c452fc98', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-func', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - gap = { - install_info = { - revision = 'ed2480d42281586932920527823b307bc45052b8', - url = 'https://github.com/gap-system/tree-sitter-gap', - }, - maintainers = { '@reiniscirpons' }, - readme_note = 'GAP system', - tier = 2, - }, - gaptst = { - install_info = { - revision = '69086d7627c03e1f4baf766bcef14c60d9e92331', - url = 'https://github.com/gap-system/tree-sitter-gaptst', - }, - maintainers = { '@reiniscirpons' }, - readme_note = 'GAP system test files', - requires = { 'gap' }, - tier = 2, - }, - gdscript = { - install_info = { - revision = '9686853b696db07118ad110e440d6de0ca6498b4', - url = 'https://github.com/PrestonKnopp/tree-sitter-gdscript', - }, - readme_note = 'Godot', - tier = 3, - }, - gdshader = { - install_info = { - revision = '68268631c8b6dc093985f1246b099f81b30ea7d1', - url = 'https://github.com/airblast-dev/tree-sitter-gdshader', - }, - maintainers = { '@airblast-dev' }, - tier = 2, - }, - git_config = { - install_info = { - revision = '0fbc9f99d5a28865f9de8427fb0672d66f9d83a5', - url = 'https://github.com/the-mikedavis/tree-sitter-git-config', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - git_rebase = { - install_info = { - revision = '760ba8e34e7a68294ffb9c495e1388e030366188', - url = 'https://github.com/the-mikedavis/tree-sitter-git-rebase', - }, - maintainers = { '@gbprod' }, - tier = 2, - }, - gitattributes = { - install_info = { - revision = '1b7af09d45b579f9f288453b95ad555f1f431645', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-gitattributes', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - gitcommit = { - install_info = { - revision = '33fe8548abcc6e374feaac5724b5a2364bf23090', - url = 'https://github.com/gbprod/tree-sitter-gitcommit', - }, - maintainers = { '@gbprod' }, - tier = 2, - }, - gitignore = { - install_info = { - revision = 'f4685bf11ac466dd278449bcfe5fd014e94aa504', - url = 'https://github.com/shunsambongi/tree-sitter-gitignore', - }, - maintainers = { '@theHamsta' }, - tier = 2, - }, - gleam = { - install_info = { - revision = '0bb1b0ae1a3555180ae7b0004851da747fc230d1', - url = 'https://github.com/gleam-lang/tree-sitter-gleam', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - glimmer = { - install_info = { - revision = '88af85568bde3b91acb5d4c352ed094d0c1f9d84', - url = 'https://github.com/ember-tooling/tree-sitter-glimmer', - }, - maintainers = { '@NullVoxPopuli' }, - readme_note = 'Glimmer and Ember', - tier = 2, - }, - glimmer_javascript = { - install_info = { - revision = '5cc865a2a0a77cbfaf5062c8fcf2a9919bd54f87', - url = 'https://github.com/NullVoxPopuli/tree-sitter-glimmer-javascript', - }, - maintainers = { '@NullVoxPopuli' }, - requires = { 'ecma' }, - tier = 2, - }, - glimmer_typescript = { - install_info = { - revision = '12d98944c1d5077b957cbdb90d663a7c4d50118c', - url = 'https://github.com/NullVoxPopuli/tree-sitter-glimmer-typescript', - }, - maintainers = { '@NullVoxPopuli' }, - requires = { 'typescript' }, - tier = 2, - }, - glsl = { - install_info = { - revision = '24a6c8ef698e4480fecf8340d771fbcb5de8fbb4', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-glsl', - }, - maintainers = { '@theHamsta' }, - requires = { 'c' }, - tier = 2, - }, - gn = { - install_info = { - revision = 'bc06955bc1e3c9ff8e9b2b2a55b38b94da923c05', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-gn', - }, - maintainers = { '@amaanq' }, - readme_name = 'GN (Generate Ninja)', - tier = 2, - }, - gnuplot = { - install_info = { - revision = '8923c1e38b9634a688a6c0dce7c18c8ffb823e79', - url = 'https://github.com/dpezto/tree-sitter-gnuplot', - }, - maintainers = { '@dpezto' }, - tier = 2, - }, - go = { - install_info = { - revision = '2346a3ab1bb3857b48b29d779a1ef9799a248cd7', - url = 'https://github.com/tree-sitter/tree-sitter-go', - }, - maintainers = { '@theHamsta', '@WinWisely268' }, - tier = 2, - }, - goctl = { - install_info = { - revision = '49c43532689fe1f53e8b9e009d0521cab02c432b', - url = 'https://github.com/chaozwn/tree-sitter-goctl', - }, - maintainers = { '@chaozwn' }, - tier = 2, - }, - godot_resource = { - install_info = { - revision = '302c1895f54bf74d53a08572f7b26a6614209adc', - url = 'https://github.com/PrestonKnopp/tree-sitter-godot-resource', - }, - maintainers = { '@pierpo' }, - readme_note = 'Godot Resources', - tier = 2, - }, - gomod = { - install_info = { - revision = '2e886870578eeba1927a2dc4bd2e2b3f598c5f9a', - url = 'https://github.com/camdencheek/tree-sitter-go-mod', - }, - maintainers = { '@camdencheek' }, - tier = 2, - }, - gosum = { - install_info = { - revision = '27816eb6b7315746ae9fcf711e4e1396dc1cf237', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-go-sum', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - gotmpl = { - install_info = { - revision = 'aa71f63de226c5592dfbfc1f29949522d7c95fac', - url = 'https://github.com/ngalaiko/tree-sitter-go-template', - }, - maintainers = { '@qvalentin' }, - tier = 2, - }, - gowork = { - install_info = { - revision = '949a8a470559543857a62102c84700d291fc984c', - url = 'https://github.com/omertuc/tree-sitter-go-work', - }, - maintainers = { '@omertuc' }, - tier = 2, - }, - gpg = { - install_info = { - revision = '4024eb268c59204280f8ac71ef146b8ff5e737f6', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-gpg-config', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - graphql = { - install_info = { - revision = '5e66e961eee421786bdda8495ed1db045e06b5fe', - url = 'https://github.com/bkegley/tree-sitter-graphql', - }, - maintainers = { '@bkegley' }, - tier = 2, - }, - gren = { - install_info = { - revision = 'c36aac51a915fdfcaf178128ba1e9c2205b25930', - url = 'https://github.com/MaeBrooks/tree-sitter-gren', - }, - maintainers = { '@MaeBrooks' }, - tier = 2, - }, - groovy = { - install_info = { - revision = '781d9cd1b482a70a6b27091e5c9e14bbcab3b768', - url = 'https://github.com/murtaza64/tree-sitter-groovy', - }, - maintainers = { '@murtaza64' }, - tier = 2, - }, - groq = { - install_info = { - revision = '1fa1ab0eb391a270957e8ad8c731b492e3645649', - url = 'https://github.com/ajrussellaudio/tree-sitter-groq', - }, - maintainers = { '@ajrussellaudio' }, - tier = 2, - }, - gstlaunch = { - install_info = { - revision = '549aef253fd38a53995cda1bf55c501174372bf7', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-gstlaunch', - }, - maintainers = { '@theHamsta' }, - tier = 2, - }, - hack = { - install_info = { - revision = '1a7ded90288189746c54861ac144ede97df95081', - url = 'https://github.com/slackhq/tree-sitter-hack', - }, - tier = 2, - }, - hare = { - install_info = { - revision = 'eed7ddf6a66b596906aa8ca3d40521b8278adc6f', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-hare', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - haskell = { - install_info = { - revision = '7fa19f195803a77855f036ee7f49e4b22856e338', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-haskell', - }, - maintainers = { '@mrcjkb' }, - tier = 2, - }, - haskell_persistent = { - install_info = { - revision = '577259b4068b2c281c9ebf94c109bd50a74d5857', - url = 'https://github.com/MercuryTechnologies/tree-sitter-haskell-persistent', - }, - maintainers = { '@lykahb' }, - tier = 2, - }, - hcl = { - install_info = { - revision = '64ad62785d442eb4d45df3a1764962dafd5bc98b', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-hcl', - }, - maintainers = { '@MichaHoffmann' }, - tier = 2, - }, - heex = { - install_info = { - revision = '5842537f734d7c12685bf27d6005313e3e5a47a0', - url = 'https://github.com/connorlay/tree-sitter-heex', - }, - maintainers = { '@connorlay' }, - tier = 2, - }, - helm = { - install_info = { - location = 'dialects/helm', - revision = 'aa71f63de226c5592dfbfc1f29949522d7c95fac', - url = 'https://github.com/ngalaiko/tree-sitter-go-template', - }, - maintainers = { '@qvalentin' }, - tier = 2, - }, - hjson = { - install_info = { - revision = '02fa3b79b3ff9a296066da6277adfc3f26cbc9e0', - url = 'https://github.com/winston0410/tree-sitter-hjson', - }, - maintainers = { '@winston0410' }, - requires = { 'json' }, - tier = 2, - }, - hlsl = { - install_info = { - revision = 'bab9111922d53d43668fabb61869bec51bbcb915', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-hlsl', - }, - maintainers = { '@theHamsta' }, - requires = { 'cpp' }, - tier = 2, - }, - hlsplaylist = { - install_info = { - revision = '3bfda9271e3adb08d35f47a2102fe957009e1c55', - url = 'https://github.com/Freed-Wu/tree-sitter-hlsplaylist', - }, - maintainers = { '@Freed-Wu' }, - tier = 2, - }, - hocon = { - install_info = { - revision = 'c390f10519ae69fdb03b3e5764f5592fb6924bcc', - url = 'https://github.com/antosha417/tree-sitter-hocon', - }, - maintainers = { '@antosha417' }, - tier = 2, - }, - hoon = { - install_info = { - revision = '1545137aadcc63660c47db9ad98d02fa602655d0', - url = 'https://github.com/urbit-pilled/tree-sitter-hoon', - }, - maintainers = { '@urbit-pilled' }, - tier = 2, - }, - html = { - install_info = { - revision = '73a3947324f6efddf9e17c0ea58d454843590cc0', - url = 'https://github.com/tree-sitter/tree-sitter-html', - }, - maintainers = { '@TravonteD' }, - requires = { 'html_tags' }, - tier = 2, - }, - html_tags = { - maintainers = { '@TravonteD' }, - readme_note = 'queries required by html, astro, vue, svelte', - tier = 2, - }, - htmldjango = { - install_info = { - revision = '3a643167ad9afac5d61e092f08ff5b054576fadf', - url = 'https://github.com/interdependence/tree-sitter-htmldjango', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - http = { - install_info = { - revision = 'db8b4398de90b6d0b6c780aba96aaa2cd8e9202c', - url = 'https://github.com/rest-nvim/tree-sitter-http', - }, - maintainers = { '@amaanq', '@NTBBloodbath' }, - tier = 2, - }, - hurl = { - install_info = { - revision = '597efbd7ce9a814bb058f48eabd055b1d1e12145', - url = 'https://github.com/pfeiferj/tree-sitter-hurl', - }, - maintainers = { '@pfeiferj' }, - tier = 2, - }, - hyprlang = { - install_info = { - revision = 'cecd6b748107d9da1f7b4ca03ef95f1f71d93b8f', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-hyprlang', - }, - maintainers = { '@luckasRanarison' }, - tier = 2, - }, - idl = { - install_info = { - revision = 'fb65762a13538b397e41a5fc1e9564c9df841410', - url = 'https://github.com/cathaysia/tree-sitter-idl', - }, - maintainers = { '@cathaysia' }, - tier = 2, - }, - idris = { - install_info = { - revision = 'c56a25cf57c68ff929356db25505c1cc4c7820f6', - url = 'https://github.com/kayhide/tree-sitter-idris', - }, - tier = 2, - }, - ini = { - install_info = { - revision = 'e4018b5176132b4f3c5d6e61cea383f42288d0f5', - url = 'https://github.com/justinmk/tree-sitter-ini', - }, - maintainers = { '@theHamsta' }, - tier = 2, - }, - inko = { - install_info = { - revision = 'v0.5.1', - url = 'https://github.com/inko-lang/tree-sitter-inko', - }, - maintainers = { '@yorickpeterse' }, - tier = 1, - }, - ispc = { - install_info = { - revision = '9b2f9aec2106b94b4e099fe75e73ebd8ae707c04', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-ispc', - }, - maintainers = { '@fab4100' }, - requires = { 'c' }, - tier = 2, - }, - janet_simple = { - install_info = { - revision = 'd183186995204314700be3e9e0a48053ea16b350', - url = 'https://github.com/sogaiu/tree-sitter-janet-simple', - }, - maintainers = { '@sogaiu' }, - tier = 2, - }, - java = { - install_info = { - revision = 'e10607b45ff745f5f876bfa3e94fbcc6b44bdc11', - url = 'https://github.com/tree-sitter/tree-sitter-java', - }, - maintainers = { '@p00f' }, - tier = 2, - }, - javadoc = { - install_info = { - revision = 'e2f56b4d0df08f6ed5df8bae266f9e75b340a9ab', - url = 'https://github.com/rmuir/tree-sitter-javadoc', - }, - maintainers = { '@rmuir' }, - tier = 2, - }, - javascript = { - install_info = { - revision = '58404d8cf191d69f2674a8fd507bd5776f46cb11', - url = 'https://github.com/tree-sitter/tree-sitter-javascript', - }, - maintainers = { '@steelsojka' }, - requires = { 'ecma', 'jsx' }, - tier = 2, - }, - jinja = { - install_info = { - location = 'tree-sitter-jinja', - revision = '413dba9fea354b62f6adada1815b2f504e32ffb5', - url = 'https://github.com/cathaysia/tree-sitter-jinja', - }, - maintainers = { '@cathaysia' }, - readme_note = 'basic highlighting', - requires = { 'jinja_inline' }, - tier = 2, - }, - jinja_inline = { - install_info = { - location = 'tree-sitter-jinja_inline', - revision = '413dba9fea354b62f6adada1815b2f504e32ffb5', - url = 'https://github.com/cathaysia/tree-sitter-jinja', - }, - maintainers = { '@cathaysia' }, - readme_note = 'needed for full highlighting', - tier = 2, - }, - jjdescription = { - install_info = { - revision = 'v1.0.3', - url = 'https://github.com/ribru17/tree-sitter-jjdescription', - }, - maintainers = { '@ribru17' }, - tier = 1, - }, - jq = { - install_info = { - revision = 'c204e36d2c3c6fce1f57950b12cabcc24e5cc4d9', - url = 'https://github.com/flurie/tree-sitter-jq', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - jsdoc = { - install_info = { - revision = '658d18dcdddb75c760363faa4963427a7c6b52db', - url = 'https://github.com/tree-sitter/tree-sitter-jsdoc', - }, - maintainers = { '@steelsojka' }, - tier = 2, - }, - json = { - install_info = { - revision = '001c28d7a29832b06b0e831ec77845553c89b56d', - url = 'https://github.com/tree-sitter/tree-sitter-json', - }, - maintainers = { '@steelsojka' }, - tier = 2, - }, - json5 = { - install_info = { - revision = 'aa630ef48903ab99e406a8acd2e2933077cc34e1', - url = 'https://github.com/Joakker/tree-sitter-json5', - }, - maintainers = { '@Joakker' }, - tier = 2, - }, - jsonnet = { - install_info = { - revision = 'ddd075f1939aed8147b7aa67f042eda3fce22790', - url = 'https://github.com/sourcegraph/tree-sitter-jsonnet', - }, - maintainers = { '@nawordar' }, - tier = 2, - }, - jsx = { - maintainers = { '@steelsojka' }, - readme_note = 'queries required by javascript, tsx', - tier = 2, - }, - julia = { - install_info = { - revision = '8454f266717232525ed03c7b09164b0404a03150', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-julia', - }, - maintainers = { '@clason' }, - tier = 2, - }, - just = { - install_info = { - revision = '5685543a6e64f66335e25518c9ae8ffa1dae3d01', - url = 'https://github.com/IndianBoy42/tree-sitter-just', - }, - maintainers = { '@Hubro' }, - tier = 2, - }, - kcl = { - install_info = { - revision = 'b0b2eb38009e04035a6e266c7e11e541f3caab7c', - url = 'https://github.com/kcl-lang/tree-sitter-kcl', - }, - maintainers = { '@bertbaron' }, - tier = 2, - }, - kconfig = { - install_info = { - revision = '9ac99fe4c0c27a35dc6f757cef534c646e944881', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-kconfig', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - kdl = { - install_info = { - revision = 'b37e3d58e5c5cf8d739b315d6114e02d42e66664', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-kdl', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - kitty = { - install_info = { - revision = 'fa6ab3fd32d890a0217495c96b35761e6d2dcb5b', - url = 'https://github.com/OXY2DEV/tree-sitter-kitty', - }, - maintainers = { '@OXY2DEV' }, - tier = 2, - }, - kos = { - install_info = { - revision = '03b261c1a78b71c38cf4616497f253c4a4ce118b', - url = 'https://github.com/kos-lang/tree-sitter-kos', - }, - maintainers = { '@cdragan' }, - tier = 2, - }, - kotlin = { - install_info = { - revision = '93bfeee1555d2b1442d68c44b0afde2a3b069e46', - url = 'https://github.com/fwcd/tree-sitter-kotlin', - }, - tier = 2, - }, - koto = { - install_info = { - revision = 'f8b3f62c0eed185dca1559789e78759d4bee60e5', - url = 'https://github.com/koto-lang/tree-sitter-koto', - }, - maintainers = { '@irh' }, - tier = 2, - }, - kusto = { - install_info = { - revision = '8353a1296607d6ba33db7c7e312226e5fc83e8ce', - url = 'https://github.com/Willem-J-an/tree-sitter-kusto', - }, - maintainers = { '@Willem-J-an' }, - tier = 2, - }, - lalrpop = { - install_info = { - revision = '27b0f7bb55b4cabd8f01a933d9ee6a49dbfc2192', - url = 'https://github.com/traxys/tree-sitter-lalrpop', - }, - maintainers = { '@traxys' }, - tier = 2, - }, - latex = { - install_info = { - generate = true, - revision = '7e0ecdc02926c7b9b2e0c76003d4fe7b0944f957', - url = 'https://github.com/latex-lsp/tree-sitter-latex', - }, - maintainers = { '@theHamsta', '@clason' }, - tier = 2, - }, - ledger = { - install_info = { - revision = '22a1ab8195c1f6e808679f803007756fe7638c6f', - url = 'https://github.com/cbarrete/tree-sitter-ledger', - }, - maintainers = { '@cbarrete' }, - tier = 2, - }, - leo = { - install_info = { - revision = '6bc5564917edacd070afc4d33cf5e2e677831ea9', - url = 'https://github.com/r001/tree-sitter-leo', - }, - maintainers = { '@r001' }, - tier = 2, - }, - linkerscript = { - install_info = { - revision = 'f99011a3554213b654985a4b0a65b3b032ec4621', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-linkerscript', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - liquid = { - install_info = { - revision = '9566ca79911052919fce09d26f1f655b5e093857', - url = 'https://github.com/hankthetank27/tree-sitter-liquid', - }, - maintainers = { '@hankthetank27' }, - tier = 2, - }, - liquidsoap = { - install_info = { - revision = '0169d92b0a93e9f32289533ef23abdafca579e56', - url = 'https://github.com/savonet/tree-sitter-liquidsoap', - }, - maintainers = { '@toots' }, - tier = 2, - }, - llvm = { - install_info = { - revision = '2914786ae6774d4c4e25a230f4afe16aa68fe1c1', - url = 'https://github.com/benwilliamgraham/tree-sitter-llvm', - }, - maintainers = { '@benwilliamgraham' }, - tier = 2, - }, - lua = { - install_info = { - revision = '10fe0054734eec83049514ea2e718b2a56acd0c9', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-lua', - }, - maintainers = { '@muniftanjim' }, - tier = 2, - }, - luadoc = { - install_info = { - revision = '873612aadd3f684dd4e631bdf42ea8990c57634e', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-luadoc', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - luap = { - install_info = { - revision = 'c134aaec6acf4fa95fe4aa0dc9aba3eacdbbe55a', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-luap', - }, - maintainers = { '@amaanq' }, - readme_note = 'Lua patterns', - tier = 2, - }, - luau = { - install_info = { - revision = 'a8914d6c1fc5131f8e1c13f769fa704c9f5eb02f', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-luau', - }, - maintainers = { '@amaanq' }, - requires = { 'lua' }, - tier = 2, - }, - m68k = { - install_info = { - revision = 'e128454c2210c0e0c10b68fe45ddb8fee80182a3', - url = 'https://github.com/grahambates/tree-sitter-m68k', - }, - maintainers = { '@grahambates' }, - tier = 2, - }, - make = { - install_info = { - revision = '70613f3d812cbabbd7f38d104d60a409c4008b43', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-make', - }, - maintainers = { '@lewis6991' }, - tier = 2, - }, - markdown = { - install_info = { - location = 'tree-sitter-markdown', - revision = 'f969cd3ae3f9fbd4e43205431d0ae286014c05b5', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-markdown', - }, - maintainers = { '@MDeiml' }, - readme_note = 'basic highlighting', - requires = { 'markdown_inline' }, - tier = 2, - }, - markdown_inline = { - install_info = { - location = 'tree-sitter-markdown-inline', - revision = 'f969cd3ae3f9fbd4e43205431d0ae286014c05b5', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-markdown', - }, - maintainers = { '@MDeiml' }, - readme_note = 'needed for full highlighting', - tier = 2, - }, - matlab = { - install_info = { - revision = 'c2390a59016f74e7d5f75ef09510768b4f30217e', - url = 'https://github.com/acristoffers/tree-sitter-matlab', - }, - maintainers = { '@acristoffers' }, - tier = 2, - }, - menhir = { - install_info = { - revision = 'be8866a6bcc2b563ab0de895af69daeffa88fe70', - url = 'https://github.com/Kerl13/tree-sitter-menhir', - }, - maintainers = { '@Kerl13' }, - tier = 2, - }, - mermaid = { - install_info = { - revision = '90ae195b31933ceb9d079abfa8a3ad0a36fee4cc', - url = 'https://github.com/monaqa/tree-sitter-mermaid', - }, - tier = 2, - }, - meson = { - install_info = { - revision = 'c84f3540624b81fc44067030afce2ff78d6ede05', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-meson', - }, - maintainers = { '@Decodetalkers' }, - tier = 2, - }, - mlir = { - install_info = { - generate = true, - revision = '96fa0adc3028cc6a9d281370c9f213a457c4a2d0', - url = 'https://github.com/artagnon/tree-sitter-mlir', - }, - maintainers = { '@artagnon' }, - tier = 2, - }, - muttrc = { - install_info = { - revision = '173b0ab53a9c07962c9777189c4c70e90f1c1837', - url = 'https://github.com/neomutt/tree-sitter-muttrc', - }, - maintainers = { '@Freed-Wu' }, - tier = 2, - }, - nasm = { - install_info = { - revision = 'd1b3638d017f2a8585e26dcfc66fe1df94185e30', - url = 'https://github.com/naclsn/tree-sitter-nasm', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - nginx = { - install_info = { - revision = '47ade644d754cce57974aac44d2c9450e823d4f4', - url = 'https://github.com/opa-oz/tree-sitter-nginx', - }, - maintainers = { '@opa-oz' }, - tier = 2, - }, - nickel = { - install_info = { - revision = 'b5b6cc3bc7b9ea19f78fed264190685419cd17a8', - url = 'https://github.com/nickel-lang/tree-sitter-nickel', - }, - tier = 2, - }, - nim = { - install_info = { - revision = '3878440d9398515ae053c6f6024986e69868bb74', - url = 'https://github.com/alaviss/tree-sitter-nim', - }, - maintainers = { '@aMOPel' }, - requires = { 'nim_format_string' }, - tier = 2, - }, - nim_format_string = { - install_info = { - revision = 'd45f75022d147cda056e98bfba68222c9c8eca3a', - url = 'https://github.com/aMOPel/tree-sitter-nim-format-string', - }, - maintainers = { '@aMOPel' }, - tier = 2, - }, - ninja = { - install_info = { - revision = '0a95cfdc0745b6ae82f60d3a339b37f19b7b9267', - url = 'https://github.com/alemuller/tree-sitter-ninja', - }, - maintainers = { '@alemuller' }, - tier = 2, - }, - nix = { - install_info = { - revision = 'eabf96807ea4ab6d6c7f09b671a88cd483542840', - url = 'https://github.com/nix-community/tree-sitter-nix', - }, - maintainers = { '@leo60228', '@mrcjkb', '@zimbatm' }, - tier = 2, - }, - nqc = { - install_info = { - revision = '14e6da1627aaef21d2b2aa0c37d04269766dcc1d', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-nqc', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - nu = { - install_info = { - revision = '696d257f6b652edb50878a783b30ad7833dec49e', - url = 'https://github.com/nushell/tree-sitter-nu', - }, - maintainers = { '@abhisheksingh0x558' }, - tier = 2, - }, - objc = { - install_info = { - revision = '181a81b8f23a2d593e7ab4259981f50122909fda', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-objc', - }, - maintainers = { '@amaanq' }, - requires = { 'c' }, - tier = 2, - }, - objdump = { - install_info = { - revision = '28d3b2e25a0b1881d1b47ed1924ca276c7003d45', - url = 'https://github.com/ColinKennedy/tree-sitter-objdump', - }, - maintainers = { '@ColinKennedy' }, - tier = 2, - }, - ocaml = { - install_info = { - location = 'grammars/ocaml', - revision = '5a979b3ec7f1fe990b8e8c4412294a0cf7228e45', - url = 'https://github.com/tree-sitter/tree-sitter-ocaml', - }, - maintainers = { '@undu' }, - tier = 2, - }, - ocaml_interface = { - install_info = { - location = 'grammars/interface', - revision = '5a979b3ec7f1fe990b8e8c4412294a0cf7228e45', - url = 'https://github.com/tree-sitter/tree-sitter-ocaml', - }, - maintainers = { '@undu' }, - requires = { 'ocaml' }, - tier = 2, - }, - ocamllex = { - install_info = { - generate = true, - revision = '33722b8be73079946a7c6dd9598e3f57956ed36d', - url = 'https://github.com/atom-ocaml/tree-sitter-ocamllex', - }, - maintainers = { '@undu' }, - tier = 2, - }, - odin = { - install_info = { - revision = 'd2ca8efb4487e156a60d5bd6db2598b872629403', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-odin', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - pascal = { - install_info = { - revision = '042119eca2e18a60e56317fb06ee3ba5c32cb447', - url = 'https://github.com/Isopod/tree-sitter-pascal', - }, - maintainers = { '@Isopod' }, - tier = 2, - }, - passwd = { - install_info = { - revision = '20239395eacdc2e0923a7e5683ad3605aee7b716', - url = 'https://github.com/ath3/tree-sitter-passwd', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - pem = { - install_info = { - revision = 'e525b177a229b1154fd81bc0691f943028d9e685', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-pem', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - perl = { - install_info = { - generate = true, - revision = 'ea9667dc65a816acace002a2b1b099978785ca33', - url = 'https://github.com/tree-sitter-perl/tree-sitter-perl', - }, - maintainers = { '@RabbiVeesh', '@LeoNerd' }, - tier = 2, - }, - php = { - install_info = { - location = 'php', - revision = '3f2465c217d0a966d41e584b42d75522f2a3149e', - url = 'https://github.com/tree-sitter/tree-sitter-php', - }, - maintainers = { '@tk-shirasaka', '@calebdw' }, - readme_note = 'PHP with embedded HTML', - requires = { 'php_only' }, - tier = 2, - }, - php_only = { - install_info = { - location = 'php_only', - revision = '3f2465c217d0a966d41e584b42d75522f2a3149e', - url = 'https://github.com/tree-sitter/tree-sitter-php', - }, - maintainers = { '@tk-shirasaka', '@calebdw' }, - readme_note = 'PHP without embedded HTML', - tier = 2, - }, - phpdoc = { - install_info = { - revision = '12d50307e6c02e5f4f876fa6cf2edea1f7808c0d', - url = 'https://github.com/claytonrcarter/tree-sitter-phpdoc', - }, - maintainers = { '@mikehaertl' }, - tier = 2, - }, - pioasm = { - install_info = { - revision = 'afece58efdb30440bddd151ef1347fa8d6f744a9', - url = 'https://github.com/leo60228/tree-sitter-pioasm', - }, - maintainers = { '@leo60228' }, - tier = 2, - }, - pkl = { - install_info = { - revision = 'f5beed1da8e5fc856a1a11e29a929d0b7cdcfe3c', - url = 'https://github.com/apple/tree-sitter-pkl', - }, - maintainers = { '@ribru17' }, - tier = 2, - }, - po = { - install_info = { - revision = 'bd860a0f57f697162bf28e576674be9c1500db5e', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-po', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - pod = { - install_info = { - generate = true, - revision = '57c606aa3373ba876d44113d13fe7bdc2c060723', - url = 'https://github.com/tree-sitter-perl/tree-sitter-pod', - }, - maintainers = { '@RabbiVeesh', '@LeoNerd' }, - tier = 2, - }, - poe_filter = { - install_info = { - revision = '205a7d576984feb38a9fc2d8cfe729617f9e0548', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-poe-filter', - }, - maintainers = { '@ObserverOfTime' }, - readme_note = 'Path of Exile item filter', - tier = 2, - }, - pony = { - install_info = { - revision = '73ff874ae4c9e9b45462673cbc0a1e350e2522a7', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-pony', - }, - maintainers = { '@amaanq', '@mfelsche' }, - tier = 2, - }, - powershell = { - filetype = 'ps1', - install_info = { - revision = '73800ecc8bddeee8f1079a5a2e0c13c3d00269bb', - url = 'https://github.com/airbus-cert/tree-sitter-powershell', - }, - maintainers = { '@L2jLiga' }, - tier = 2, - }, - printf = { - install_info = { - revision = 'ec4e5674573d5554fccb87a887c97d4aec489da7', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-printf', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - prisma = { - install_info = { - revision = '3556b2c1f20ec9ac91e92d32c43d9d2a0ca3cc49', - url = 'https://github.com/victorhqc/tree-sitter-prisma', - }, - maintainers = { '@elianiva' }, - tier = 2, - }, - problog = { - install_info = { - location = 'grammars/problog', - revision = 'd8d415f6a1cf80ca138524bcc395810b176d40fa', - url = 'https://github.com/foxyseta/tree-sitter-prolog', - }, - maintainers = { '@foxyseta' }, - requires = { 'prolog' }, - tier = 2, - }, - prolog = { - install_info = { - location = 'grammars/prolog', - revision = 'd8d415f6a1cf80ca138524bcc395810b176d40fa', - url = 'https://github.com/foxyseta/tree-sitter-prolog', - }, - maintainers = { '@foxyseta' }, - tier = 2, - }, - promql = { - install_info = { - revision = '77625d78eebc3ffc44d114a07b2f348dff3061b0', - url = 'https://github.com/MichaHoffmann/tree-sitter-promql', - }, - maintainers = { '@MichaHoffmann' }, - tier = 2, - }, - properties = { - install_info = { - revision = '6310671b24d4e04b803577b1c675d765cbd5773b', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-properties', - }, - maintainers = { '@ObserverOfTime' }, - readme_note = 'Java properties files', - tier = 2, - }, - proto = { - install_info = { - revision = 'd65a18ce7c2242801f702770114ad08056c7f8c9', - url = 'https://github.com/coder3101/tree-sitter-proto', - }, - maintainers = { '@stefanvanburen' }, - tier = 2, - }, - prql = { - install_info = { - revision = '09e158cd3650581c0af4c49c2e5b10c4834c8646', - url = 'https://github.com/PRQL/tree-sitter-prql', - }, - maintainers = { '@matthias-Q' }, - tier = 2, - }, - psv = { - install_info = { - location = 'psv', - revision = 'f6bf6e35eb0b95fbadea4bb39cb9709507fcb181', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-csv', - }, - maintainers = { '@amaanq' }, - requires = { 'tsv' }, - tier = 2, - }, - pug = { - install_info = { - revision = '13e9195370172c86a8b88184cc358b23b677cc46', - url = 'https://github.com/zealot128/tree-sitter-pug', - }, - maintainers = { '@zealot128' }, - tier = 2, - }, - puppet = { - install_info = { - revision = '15f192929b7d317f5914de2b4accd37b349182a6', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-puppet', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - purescript = { - install_info = { - revision = 'f541f95ffd6852fbbe88636317c613285bc105af', - url = 'https://github.com/postsolar/tree-sitter-purescript', - }, - maintainers = { '@postsolar' }, - tier = 2, - }, - pymanifest = { - install_info = { - revision = 'debbdb83fe6356adc7261c41c69b45ba49c97294', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-pymanifest', - }, - maintainers = { '@ObserverOfTime' }, - readme_name = 'PyPA manifest', - tier = 2, - }, - python = { - install_info = { - revision = 'v0.25.0', - url = 'https://github.com/tree-sitter/tree-sitter-python', - }, - maintainers = { '@stsewd', '@theHamsta' }, - tier = 1, - }, - ql = { - install_info = { - revision = '1fd627a4e8bff8c24c11987474bd33112bead857', - url = 'https://github.com/tree-sitter/tree-sitter-ql', - }, - maintainers = { '@pwntester' }, - tier = 2, - }, - qmldir = { - install_info = { - revision = '6b2b5e41734bd6f07ea4c36ac20fb6f14061c841', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-qmldir', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - qmljs = { - install_info = { - revision = '0bec4359a7eb2f6c9220cd57372d87d236f66d59', - url = 'https://github.com/yuja/tree-sitter-qmljs', - }, - maintainers = { '@Decodetalkers' }, - requires = { 'ecma' }, - tier = 2, - }, - query = { - install_info = { - revision = 'fc5409c6820dd5e02b0b0a309d3da2bfcde2db17', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-query', - }, - maintainers = { '@steelsojka' }, - readme_note = 'Tree-sitter query language', - tier = 2, - }, - r = { - install_info = { - revision = '0e6ef7741712c09dc3ee6e81c42e919820cc65ef', - url = 'https://github.com/r-lib/tree-sitter-r', - }, - maintainers = { '@ribru17' }, - tier = 2, - }, - racket = { - install_info = { - revision = '54649be8b939341d2d5410b594ab954fe8814bd0', - url = 'https://github.com/6cdh/tree-sitter-racket', - }, - tier = 2, - }, - ralph = { - install_info = { - revision = 'f6d81bf7a4599c77388035439cf5801cd461ff77', - url = 'https://github.com/alephium/tree-sitter-ralph', - }, - maintainers = { '@tdroxler' }, - tier = 2, - }, - rasi = { - install_info = { - revision = 'e735c6881d8b475aaa4ef8f0a2bdfd825b438143', - url = 'https://github.com/Fymyte/tree-sitter-rasi', - }, - maintainers = { '@Fymyte' }, - tier = 2, - }, - razor = { - install_info = { - revision = 'fe46ce5ea7d844e53d59bc96f2175d33691c61c5', - url = 'https://github.com/tris203/tree-sitter-razor', - }, - maintainers = { '@tris203' }, - tier = 2, - }, - rbs = { - install_info = { - revision = '5282e2f36d4109f5315c1d9486b5b0c2044622bb', - url = 'https://github.com/joker1007/tree-sitter-rbs', - }, - maintainers = { '@joker1007' }, - tier = 2, - }, - re2c = { - install_info = { - revision = 'c18a3c2f4b6665e35b7e50d6048ea3cff770c572', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-re2c', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - readline = { - install_info = { - revision = '6b744c527aebd12e46a5ecb3aebdb8d621a8e83e', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-readline', - }, - maintainers = { '@ribru17' }, - tier = 2, - }, - regex = { - install_info = { - revision = 'b2ac15e27fce703d2f37a79ccd94a5c0cbe9720b', - url = 'https://github.com/tree-sitter/tree-sitter-regex', - }, - maintainers = { '@theHamsta' }, - tier = 2, - }, - rego = { - install_info = { - revision = 'ddd39af81fe8b0288102a7cb97959dfce723e0f3', - url = 'https://github.com/FallenAngel97/tree-sitter-rego', - }, - maintainers = { '@FallenAngel97' }, - tier = 2, - }, - requirements = { - install_info = { - revision = 'caeb2ba854dea55931f76034978de1fd79362939', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-requirements', - }, - maintainers = { '@ObserverOfTime' }, - readme_name = 'pip requirements', - tier = 2, - }, - rescript = { - install_info = { - revision = '43c2f1f35024918d415dc933d4cc534d6419fedf', - url = 'https://github.com/rescript-lang/tree-sitter-rescript', - }, - maintainers = { '@ribru17' }, - tier = 2, - }, - rifleconf = { - install_info = { - revision = '6389ef0fc0d48f0397ec233109c074a0cb685e36', - url = 'https://github.com/purarue/tree-sitter-rifleconf', - }, - maintainers = { '@purarue' }, - tier = 2, - }, - rnoweb = { - install_info = { - revision = '1a74dc0ed731ad07db39f063e2c5a6fe528cae7f', - url = 'https://github.com/bamonroe/tree-sitter-rnoweb', - }, - maintainers = { '@bamonroe' }, - tier = 2, - }, - robot = { - install_info = { - revision = 'v1.3.0', - url = 'https://github.com/Hubro/tree-sitter-robot', - }, - tier = 3, - }, - robots_txt = { - install_info = { - revision = '0c066107e3548de79316a6a4ec771e2f7cf7c468', - url = 'https://github.com/opa-oz/tree-sitter-robots-txt', - }, - maintainers = { '@opa-oz' }, - tier = 2, - }, - roc = { - install_info = { - revision = '40e52f343f1b1f270d6ecb2ca898ca9b8cba6936', - url = 'https://github.com/faldor20/tree-sitter-roc', - }, - tier = 3, - }, - ron = { - install_info = { - revision = '78938553b93075e638035f624973083451b29055', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-ron', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - rst = { - install_info = { - revision = '4e562e1598b95b93db4f3f64fe40ddefbc677a15', - url = 'https://github.com/stsewd/tree-sitter-rst', - }, - maintainers = { '@stsewd' }, - tier = 2, - }, - ruby = { - install_info = { - revision = 'ad907a69da0c8a4f7a943a7fe012712208da6dee', - url = 'https://github.com/tree-sitter/tree-sitter-ruby', - }, - maintainers = { '@TravonteD' }, - tier = 2, - }, - runescript = { - install_info = { - revision = 'cf85bbd5da0c5ad243301d889c7f84d790a4cae4', - url = 'https://github.com/2004Scape/tree-sitter-runescript', - }, - maintainers = { '@2004Scape' }, - tier = 2, - }, - rust = { - install_info = { - revision = '77a3747266f4d621d0757825e6b11edcbf991ca5', - url = 'https://github.com/tree-sitter/tree-sitter-rust', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - scala = { - install_info = { - revision = '14c5cfd2b8e0f057ba0f4f72ee4812b0ae6cdce3', - url = 'https://github.com/tree-sitter/tree-sitter-scala', - }, - maintainers = { '@stevanmilic' }, - tier = 2, - }, - scfg = { - install_info = { - revision = 'd850fd470445d73de318a21d734d1e09e29b773c', - url = 'https://github.com/rockorager/tree-sitter-scfg', - }, - maintainers = { '@WhyNotHugo' }, - tier = 2, - }, - scheme = { - install_info = { - revision = 'c6cb7c7d7a04b3f5d999c28e2e9c0c31b2d50ece', - url = 'https://github.com/6cdh/tree-sitter-scheme', - }, - tier = 2, - }, - scss = { - install_info = { - revision = 'c478c6868648eff49eb04a4df90d703dc45b312a', - url = 'https://github.com/serenadeai/tree-sitter-scss', - }, - maintainers = { '@elianiva' }, - requires = { 'css' }, - tier = 2, - }, - sflog = { - install_info = { - location = 'sflog', - revision = '3597575a429766dd7ecce9f5bb97f6fec4419d5d', - url = 'https://github.com/aheber/tree-sitter-sfapex', - }, - maintainers = { '@aheber', '@xixiaofinland' }, - readme_note = 'Salesforce debug log', - tier = 2, - }, - slang = { - install_info = { - revision = '1dbcc4abc7b3cdd663eb03d93031167d6ed19f56', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-slang', - }, - maintainers = { '@theHamsta' }, - readme_note = 'Shader Slang', - tier = 2, - }, - slim = { - install_info = { - revision = 'a06113f5175b805a37d20df0a6f9d722e0ab6cfe', - url = 'https://github.com/theoo/tree-sitter-slim', - }, - maintainers = { '@theoo' }, - tier = 2, - }, - slint = { - install_info = { - revision = '4d7ad0617c30f865f051bbac04a9826bea29f987', - url = 'https://github.com/slint-ui/tree-sitter-slint', - }, - maintainers = { '@hunger' }, - tier = 2, - }, - smali = { - install_info = { - revision = 'fdfa6a1febc43c7467aa7e937b87b607956f2346', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-smali', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - smithy = { - install_info = { - revision = 'ec4fe14586f2b0a1bc65d6db17f8d8acd8a90433', - url = 'https://github.com/indoorvivants/tree-sitter-smithy', - }, - maintainers = { '@amaanq', '@keynmol' }, - tier = 2, - }, - snakemake = { - install_info = { - revision = '68010430c3e51c0e84c1ce21c6551df0e2469f51', - url = 'https://github.com/osthomas/tree-sitter-snakemake', - }, - maintainers = { '@osthomas' }, - tier = 2, - }, - snl = { - install_info = { - revision = '846e2d6809ac5863a15b5494f20fd267c21221c8', - url = 'https://github.com/minijackson/tree-sitter-snl', - }, - maintainers = { '@minijackson' }, - readme_note = "EPICS Sequencer's SNL files", - tier = 2, - }, - solidity = { - install_info = { - revision = '048fe686cb1fde267243739b8bdbec8fc3a55272', - url = 'https://github.com/JoranHonig/tree-sitter-solidity', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - soql = { - install_info = { - location = 'soql', - revision = '3597575a429766dd7ecce9f5bb97f6fec4419d5d', - url = 'https://github.com/aheber/tree-sitter-sfapex', - }, - maintainers = { '@aheber', '@xixiafinland' }, - tier = 2, - }, - sosl = { - install_info = { - location = 'sosl', - revision = '3597575a429766dd7ecce9f5bb97f6fec4419d5d', - url = 'https://github.com/aheber/tree-sitter-sfapex', - }, - maintainers = { '@aheber', '@xixiafinland' }, - tier = 2, - }, - sourcepawn = { - install_info = { - revision = '5a8fdd446b516c81e218245c12129c6ad4bccfa2', - url = 'https://github.com/nilshelmig/tree-sitter-sourcepawn', - }, - maintainers = { '@Sarrus1' }, - tier = 2, - }, - sparql = { - install_info = { - revision = '1ef52d35a73a2a5f2e433ecfd1c751c1360a923b', - url = 'https://github.com/GordianDziwis/tree-sitter-sparql', - }, - maintainers = { '@GordianDziwis' }, - tier = 2, - }, - sproto = { - install_info = { - revision = 'd554c1456e35e7b2690552d52921c987d0cf6799', - url = 'https://github.com/hanxi/tree-sitter-sproto', - }, - maintainers = { '@hanxi' }, - tier = 2, - }, - sql = { - install_info = { - branch = 'gh-pages', - revision = '851e9cb257ba7c66cc8c14214a31c44d2f1e954e', - url = 'https://github.com/derekstride/tree-sitter-sql', - }, - maintainers = { '@derekstride' }, - tier = 2, - }, - squirrel = { - install_info = { - revision = '072c969749e66f000dba35a33c387650e203e96e', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-squirrel', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - ssh_config = { - install_info = { - revision = '71d2693deadaca8cdc09e38ba41d2f6042da1616', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-ssh-config', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - starlark = { - install_info = { - revision = 'a453dbf3ba433db0e5ec621a38a7e59d72e4dc69', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-starlark', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - strace = { - install_info = { - revision = 'ac874ddfcc08d689fee1f4533789e06d88388f29', - url = 'https://github.com/sigmaSd/tree-sitter-strace', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - styled = { - install_info = { - revision = '319cdcaa0346ba6db668a222d938e5c3569e2a51', - url = 'https://github.com/mskelton/tree-sitter-styled', - }, - maintainers = { '@mskelton' }, - tier = 2, - }, - supercollider = { - install_info = { - revision = '2b03ff49dd19b046add072d0861c4d1ca8a384c8', - url = 'https://github.com/madskjeldgaard/tree-sitter-supercollider', - }, - maintainers = { '@madskjeldgaard', '@elgiano' }, - tier = 2, - }, - superhtml = { - install_info = { - location = 'tree-sitter-superhtml', - revision = '8b5bb272b269afdd38cdf641c4a707dd92fbe902', - url = 'https://github.com/kristoff-it/superhtml', - }, - maintainers = { '@rockorager' }, - tier = 2, - }, - surface = { - install_info = { - revision = 'f4586b35ac8548667a9aaa4eae44456c1f43d032', - url = 'https://github.com/connorlay/tree-sitter-surface', - }, - maintainers = { '@connorlay' }, - tier = 2, - }, - svelte = { - install_info = { - revision = 'ae5199db47757f785e43a14b332118a5474de1a2', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-svelte', - }, - maintainers = { '@amaanq' }, - requires = { 'html_tags' }, - tier = 2, - }, - sway = { - install_info = { - revision = '9b7845ce06ecb38b040c3940970b4fd0adc331d1', - url = 'https://github.com/FuelLabs/tree-sitter-sway.git', - }, - maintainers = { '@ribru17' }, - tier = 2, - }, - swift = { - install_info = { - generate = true, - revision = '8abb3e8b33256d89127a35e87480736f74755ff9', - url = 'https://github.com/alex-pinkus/tree-sitter-swift', - }, - maintainers = { '@alex-pinkus' }, - tier = 2, - }, - sxhkdrc = { - install_info = { - revision = '440d5f913d9465c9c776a1bd92334d32febcf065', - url = 'https://github.com/RaafatTurki/tree-sitter-sxhkdrc', - }, - maintainers = { '@RaafatTurki' }, - tier = 2, - }, - systemtap = { - install_info = { - revision = 'f2b378a9af0b7e1192cff67a5fb45508c927205d', - url = 'https://github.com/ok-ryoko/tree-sitter-systemtap', - }, - maintainers = { '@ok-ryoko' }, - tier = 2, - }, - systemverilog = { - install_info = { - revision = '293928578cb27fbd0005fcc5f09c09a1e8628c89', - url = 'https://github.com/gmlarumbe/tree-sitter-systemverilog', - }, - maintainers = { '@zhangwwpeng' }, - tier = 2, - }, - t32 = { - install_info = { - revision = '3bce3977303c3f88bfa9fcdfcfd1a4f8f6ffa0b0', - url = 'https://github.com/xasc/tree-sitter-t32', - }, - maintainers = { '@xasc' }, - tier = 2, - }, - tablegen = { - install_info = { - revision = 'b1170880c61355aaf38fc06f4af7d3c55abdabc4', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-tablegen', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - tact = { - install_info = { - revision = 'a6267c2091ed432c248780cec9f8d42c8766d9ad', - url = 'https://github.com/tact-lang/tree-sitter-tact', - }, - maintainers = { '@novusnota' }, - tier = 2, - }, - tcl = { - install_info = { - revision = '8f11ac7206a54ed11210491cee1e0657e2962c47', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-tcl', - }, - maintainers = { '@lewis6991' }, - tier = 2, - }, - teal = { - install_info = { - generate = true, - revision = '05d276e737055e6f77a21335b7573c9d3c091e2f', - url = 'https://github.com/euclidianAce/tree-sitter-teal', - }, - maintainers = { '@euclidianAce' }, - tier = 2, - }, - templ = { - install_info = { - revision = '1c6db04effbcd7773c826bded9783cbc3061bd55', - url = 'https://github.com/vrischmann/tree-sitter-templ', - }, - maintainers = { '@vrischmann' }, - tier = 2, - }, - tera = { - install_info = { - revision = '3a38c368e806268daac9923a27e72bcafbbc16bb', - url = 'https://github.com/uncenter/tree-sitter-tera', - }, - maintainers = { '@uncenter' }, - tier = 2, - }, - terraform = { - install_info = { - location = 'dialects/terraform', - revision = '64ad62785d442eb4d45df3a1764962dafd5bc98b', - url = 'https://github.com/MichaHoffmann/tree-sitter-hcl', - }, - maintainers = { '@MichaHoffmann' }, - requires = { 'hcl' }, - tier = 2, - }, - textproto = { - install_info = { - revision = '568471b80fd8793d37ed01865d8c2208a9fefd1b', - url = 'https://github.com/PorterAtGoogle/tree-sitter-textproto', - }, - maintainers = { '@Porter' }, - tier = 2, - }, - thrift = { - install_info = { - revision = '68fd0d80943a828d9e6f49c58a74be1e9ca142cf', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-thrift', - }, - maintainers = { '@amaanq', '@duskmoon314' }, - tier = 2, - }, - tiger = { - install_info = { - revision = '4a77b2d7a004587646bddc4e854779044b6db459', - url = 'https://github.com/ambroisie/tree-sitter-tiger', - }, - maintainers = { '@ambroisie' }, - tier = 2, - }, - tlaplus = { - install_info = { - revision = 'add40814fda369f6efd989977b2c498aaddde984', - url = 'https://github.com/tlaplus-community/tree-sitter-tlaplus', - }, - maintainers = { '@ahelwer', '@susliko' }, - tier = 2, - }, - tmux = { - install_info = { - revision = '75d1b995b0c23400ac8e49db757a2e0386f9fa8f', - url = 'https://github.com/Freed-Wu/tree-sitter-tmux', - }, - maintainers = { '@Freed-Wu', '@stevenxxiu' }, - tier = 2, - }, - todotxt = { - install_info = { - revision = '3937c5cd105ec4127448651a21aef45f52d19609', - url = 'https://github.com/arnarg/tree-sitter-todotxt', - }, - maintainers = { '@arnarg' }, - tier = 2, - }, - toml = { - install_info = { - revision = '64b56832c2cffe41758f28e05c756a3a98d16f41', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-toml', - }, - maintainers = { '@tk-shirasaka' }, - tier = 2, - }, - tsv = { - install_info = { - location = 'tsv', - revision = 'f6bf6e35eb0b95fbadea4bb39cb9709507fcb181', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-csv', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - tsx = { - install_info = { - location = 'tsx', - revision = '75b3874edb2dc714fb1fd77a32013d0f8699989f', - url = 'https://github.com/tree-sitter/tree-sitter-typescript', - }, - maintainers = { '@steelsojka' }, - requires = { 'ecma', 'jsx', 'typescript' }, - tier = 2, - }, - turtle = { - install_info = { - revision = '7f789ea7ef765080f71a298fc96b7c957fa24422', - url = 'https://github.com/GordianDziwis/tree-sitter-turtle', - }, - maintainers = { '@GordianDziwis' }, - tier = 2, - }, - twig = { - install_info = { - revision = '7195ee573ab5c3b3bb0e91b042e6f83ac1b11104', - url = 'https://github.com/gbprod/tree-sitter-twig', - }, - maintainers = { '@gbprod' }, - tier = 2, - }, - typescript = { - install_info = { - location = 'typescript', - revision = '75b3874edb2dc714fb1fd77a32013d0f8699989f', - url = 'https://github.com/tree-sitter/tree-sitter-typescript', - }, - maintainers = { '@steelsojka' }, - requires = { 'ecma' }, - tier = 2, - }, - typespec = { - install_info = { - revision = '395bef1e1eb4dd18365401642beb534e8a244056', - url = 'https://github.com/happenslol/tree-sitter-typespec', - }, - maintainers = { '@happenslol' }, - tier = 2, - }, - typoscript = { - install_info = { - revision = 'b5d0162b328ec52cf300054a8a23d47f84f55cb4', - url = 'https://github.com/Teddytrombone/tree-sitter-typoscript', - }, - maintainers = { '@Teddytrombone' }, - tier = 2, - }, - typst = { - install_info = { - revision = '46cf4ded12ee974a70bf8457263b67ad7ee0379d', - url = 'https://github.com/uben0/tree-sitter-typst', - }, - maintainers = { '@uben0', '@RaafatTurki' }, - tier = 2, - }, - udev = { - install_info = { - revision = '2fcb563a4d56a6b8e8c129252325fc6335e4acbf', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-udev', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - ungrammar = { - install_info = { - revision = 'debd26fed283d80456ebafa33a06957b0c52e451', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-ungrammar', - }, - maintainers = { '@Philipp-M', '@amaanq' }, - tier = 2, - }, - unison = { - install_info = { - generate = true, - revision = '10365cc70ab2b2de85ea7ab35cf6b7636c36ce8b', - url = 'https://github.com/kylegoetz/tree-sitter-unison', - }, - maintainers = { '@tapegram' }, - tier = 2, - }, - usd = { - install_info = { - revision = '4e0875f724d94d0c2ff36f9b8cb0b12f8b20d216', - url = 'https://github.com/ColinKennedy/tree-sitter-usd', - }, - maintainers = { '@ColinKennedy' }, - tier = 2, - }, - uxntal = { - install_info = { - revision = 'ad9b638b914095320de85d59c49ab271603af048', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-uxntal', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - v = { - install_info = { - location = 'tree_sitter_v', - revision = '095865df4b9ddd21e376d635586c663d5a736f71', - url = 'https://github.com/vlang/v-analyzer', - }, - maintainers = { '@kkharji', '@amaanq' }, - tier = 2, - }, - vala = { - install_info = { - revision = '97e6db3c8c73b15a9541a458d8e797a07f588ef4', - url = 'https://github.com/vala-lang/tree-sitter-vala', - }, - maintainers = { '@Prince781' }, - tier = 2, - }, - vento = { - install_info = { - revision = 'edd6596d4b0f392b87fc345dc26d84a6c32f7059', - url = 'https://github.com/ventojs/tree-sitter-vento', - }, - tier = 3, - }, - vhdl = { - install_info = { - revision = 'c2d9be3d5ab7fb2cae8ad5ae604cd3606a4af0f2', - url = 'https://github.com/jpt13653903/tree-sitter-vhdl', - }, - maintainers = { '@jpt13653903' }, - tier = 2, - }, - vhs = { - install_info = { - revision = '0c6fae9d2cfc5b217bfd1fe84a7678f5917116db', - url = 'https://github.com/charmbracelet/tree-sitter-vhs', - }, - maintainers = { '@caarlos0' }, - tier = 2, - }, - vim = { - install_info = { - revision = '3092fcd99eb87bbd0fc434aa03650ba58bd5b43b', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-vim', - }, - maintainers = { '@clason' }, - tier = 2, - }, - vimdoc = { - install_info = { - revision = 'f061895a0eff1d5b90e4fb60d21d87be3267031a', - url = 'https://github.com/neovim/tree-sitter-vimdoc', - }, - maintainers = { '@clason' }, - tier = 2, - }, - vrl = { - install_info = { - revision = '274b3ce63f72aa8ffea18e7fc280d3062d28f0ba', - url = 'https://github.com/belltoy/tree-sitter-vrl', - }, - maintainers = { '@belltoy' }, - tier = 2, - }, - vue = { - install_info = { - revision = 'ce8011a414fdf8091f4e4071752efc376f4afb08', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-vue', - }, - maintainers = { '@WhyNotHugo', '@lucario387' }, - requires = { 'html_tags' }, - tier = 2, - }, - wgsl = { - install_info = { - revision = '40259f3c77ea856841a4e0c4c807705f3e4a2b65', - url = 'https://github.com/szebniok/tree-sitter-wgsl', - }, - maintainers = { '@szebniok' }, - tier = 2, - }, - wgsl_bevy = { - install_info = { - revision = 'd9306a798ede627001a8e5752f775858c8edd7e4', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-wgsl-bevy', - }, - maintainers = { '@theHamsta' }, - tier = 2, - }, - wing = { - install_info = { - revision = '76e0c25844a66ebc6e866d690fcc5f4e90698947', - url = 'https://github.com/winglang/tree-sitter-wing', - }, - maintainers = { '@gshpychka', '@MarkMcCulloh' }, - tier = 2, - }, - wit = { - install_info = { - revision = 'v1.3.0', - url = 'https://github.com/bytecodealliance/tree-sitter-wit', - }, - maintainers = { '@mkatychev' }, - tier = 1, - }, - wxml = { - install_info = { - revision = '7b821c748dc410332f59496c0dea2632168c4e5a', - url = 'https://github.com/BlockLune/tree-sitter-wxml', - }, - maintainers = { '@BlockLune' }, - tier = 2, - }, - xcompose = { - install_info = { - revision = 'a51d6366f041dbefec4da39a7eb3168a9b1cbc0e', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-xcompose', - }, - maintainers = { '@ObserverOfTime' }, - tier = 2, - }, - xml = { - install_info = { - location = 'xml', - revision = '5000ae8f22d11fbe93939b05c1e37cf21117162d', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-xml', - }, - maintainers = { '@ObserverOfTime' }, - requires = { 'dtd' }, - tier = 2, - }, - xresources = { - install_info = { - revision = 'v1.0.0', - url = 'https://github.com/ValdezFOmar/tree-sitter-xresources', - }, - maintainers = { '@ValdezFOmar' }, - tier = 1, - }, - yaml = { - install_info = { - revision = '4463985dfccc640f3d6991e3396a2047610cf5f8', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-yaml', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - yang = { - install_info = { - revision = '2c0e6be8dd4dcb961c345fa35c309ad4f5bd3502', - url = 'https://github.com/Hubro/tree-sitter-yang', - }, - maintainers = { '@Hubro' }, - tier = 2, - }, - yuck = { - install_info = { - revision = '6c60112b3b3e739fb1ca4a8ea4bea2b6ffe11318', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-yuck', - }, - maintainers = { '@Philipp-M', '@amaanq' }, - tier = 2, - }, - zathurarc = { - install_info = { - revision = '0554b4a5d313244b7fc000cbb41c04afae4f4e31', - url = 'https://github.com/Freed-Wu/tree-sitter-zathurarc', - }, - maintainers = { '@Freed-Wu' }, - tier = 2, - }, - zig = { - install_info = { - revision = '6479aa13f32f701c383083d8b28360ebd682fb7d', - url = 'https://github.com/tree-sitter-grammars/tree-sitter-zig', - }, - maintainers = { '@amaanq' }, - tier = 2, - }, - ziggy = { - install_info = { - location = 'tree-sitter-ziggy', - revision = '4353b20ef2ac750e35c6d68e4eb2a07c2d7cf901', - url = 'https://github.com/kristoff-it/ziggy', - }, - tier = 3, - }, - ziggy_schema = { - install_info = { - location = 'tree-sitter-ziggy-schema', - revision = '4353b20ef2ac750e35c6d68e4eb2a07c2d7cf901', - url = 'https://github.com/kristoff-it/ziggy', - }, - tier = 3, - }, - zsh = { - install_info = { - revision = 'bd344c23a7683e293d077c6648e88f209782fedb', - url = 'https://github.com/georgeharker/tree-sitter-zsh', - }, - maintainers = { '@georgeharker' }, - tier = 2, +local api = vim.api +local ts = vim.treesitter + +local filetype_to_parsername = { + javascriptreact = "javascript", + ecma = "javascript", + jsx = "javascript", + PKGBUILD = "bash", + html_tags = "html", + ["typescript.tsx"] = "tsx", + terraform = "hcl", + ["html.handlebars"] = "glimmer", + systemverilog = "verilog", + cls = "latex", + sty = "latex", + OpenFOAM = "foam", + pandoc = "markdown", + rmd = "markdown", + cs = "c_sharp", + tape = "vhs", +} + +---@class InstallInfo +---@field url string +---@field branch string|nil +---@field revision string|nil +---@field files string[] +---@field generate_requires_npm boolean|nil +---@field requires_generate_from_grammar boolean|nil +---@field location string|nil + +---@class ParserInfo +---@field install_info InstallInfo +---@field filetype string +---@field maintainers string[] +---@field experimental boolean|nil + +---@type ParserInfo[] +local list = setmetatable({}, { + __newindex = function(table, parsername, parserconfig) + rawset( + table, + parsername, + setmetatable(parserconfig, { + __newindex = function(parserconfigtable, key, value) + if key == "used_by" then + require("nvim-treesitter.utils").notify( + "used_by is deprecated, please use 'filetype_to_parsername'", + vim.log.levels.WARN + ) + filetype_to_parsername[value] = parsername + else + rawset(parserconfigtable, key, value) + end + end, + }) + ) + + filetype_to_parsername[parserconfig.filetype or parsername] = parsername + end, +}) + +list.agda = { + install_info = { + url = "https://github.com/AusCyberman/tree-sitter-agda", + branch = "master", + files = { "src/parser.c", "src/scanner.cc" }, + generate_requires_npm = true, + }, + filetype = "agda", + maintainers = { "@Decodetalkers" }, +} + +list.meson = { + install_info = { + url = "https://github.com/Decodetalkers/tree-sitter-meson", + branch = "master", + files = { "src/parser.c" }, + }, + filetype = "meson", + maintainers = { "@Decodetalkers" }, +} + +list.qmljs = { + install_info = { + url = "https://github.com/yuja/tree-sitter-qmljs", + branch = "master", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "qmljs", + maintainers = { "@Decodetalkers" }, +} + +list.racket = { + install_info = { + url = "https://github.com/6cdh/tree-sitter-racket", + branch = "main", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@6cdh" }, +} + +list.scheme = { + install_info = { + url = "https://github.com/6cdh/tree-sitter-scheme", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@6cdh" }, +} + +list.javascript = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-javascript", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@steelsojka" }, +} + +list.rego = { + install_info = { + url = "https://github.com/FallenAngel97/tree-sitter-rego", + files = { "src/parser.c" }, + }, + maintainers = { "@FallenAngel97" }, + filetype = "rego", +} + +list.c = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-c", + files = { "src/parser.c" }, + }, + maintainers = { "@vigoux" }, +} + +list.embedded_template = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-embedded-template", + files = { "src/parser.c" }, + }, + filetype = "eruby", +} + +list.clojure = { + install_info = { + url = "https://github.com/sogaiu/tree-sitter-clojure", + files = { "src/parser.c" }, + }, + maintainers = { "@sogaiu" }, +} + +list.commonlisp = { + install_info = { + url = "https://github.com/theHamsta/tree-sitter-commonlisp", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + filetype = "lisp", + maintainers = { "@theHamsta" }, +} + +list.cpp = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-cpp", + files = { "src/parser.c", "src/scanner.cc" }, + generate_requires_npm = true, + }, + maintainers = { "@theHamsta" }, +} + +list.cuda = { + install_info = { + url = "https://github.com/theHamsta/tree-sitter-cuda", + files = { "src/parser.c", "src/scanner.cc" }, + generate_requires_npm = true, + }, + maintainers = { "@theHamsta" }, +} + +list.d = { + install_info = { + url = "https://github.com/CyberShadow/tree-sitter-d", + files = { "src/parser.c", "src/scanner.cc" }, + requires_generate_from_grammar = true, + }, + maintainers = { "@nawordar" }, + -- Generating grammar takes ~60s + experimental = true, +} + +list.glsl = { + install_info = { + url = "https://github.com/theHamsta/tree-sitter-glsl", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + maintainers = { "@theHamsta" }, +} + +list.hlsl = { + install_info = { + url = "https://github.com/theHamsta/tree-sitter-hlsl", + files = { "src/parser.c", "src/scanner.cc" }, + generate_requires_npm = true, + }, + maintainers = { "@theHamsta" }, +} + +list.dockerfile = { + install_info = { + url = "https://github.com/camdencheek/tree-sitter-dockerfile", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@camdencheek" }, +} + +list.dot = { + install_info = { + url = "https://github.com/rydesun/tree-sitter-dot", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@rydesun" }, +} + +list.rust = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-rust", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@vigoux" }, +} + +list.fusion = { + install_info = { + url = "https://gitlab.com/jirgn/tree-sitter-fusion.git", + files = { "src/parser.c", "src/scanner.c" }, + branch = "main", + }, + maintainers = { "@jirgn" }, +} + +list.ledger = { + install_info = { + url = "https://github.com/cbarrete/tree-sitter-ledger", + files = { "src/parser.c" }, + }, + maintainers = { "@cbarrete" }, +} + +list.lua = { + install_info = { + url = "https://github.com/MunifTanjim/tree-sitter-lua", + branch = "main", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@muniftanjim" }, +} + +list.python = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-python", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@stsewd", "@theHamsta" }, +} + +list.go = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-go", + files = { "src/parser.c" }, + }, + maintainers = { "@theHamsta", "@WinWisely268" }, +} + +list.gomod = { + install_info = { + url = "https://github.com/camdencheek/tree-sitter-go-mod", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@camdencheek" }, + filetype = "gomod", +} + +list.gowork = { + install_info = { + url = "https://github.com/omertuc/tree-sitter-go-work", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@omertuc" }, + filetype = "gowork", +} + +list.graphql = { + install_info = { + url = "https://github.com/bkegley/tree-sitter-graphql", + files = { "src/parser.c" }, + }, + maintainers = { "@bkegley" }, +} + +list.ruby = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-ruby", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@TravonteD" }, +} + +list.perl = { + install_info = { + url = "https://github.com/ganezdragon/tree-sitter-perl", + files = { "src/parser.c", "src/scanner.cc" }, + generate_requires_npm = true, + }, + maintainers = { "@lcrownover" }, +} + +list.bash = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-bash", + files = { "src/parser.c", "src/scanner.cc" }, + }, + filetype = "sh", + maintainers = { "@TravonteD" }, +} + +list.fish = { + install_info = { + url = "https://github.com/ram02z/tree-sitter-fish", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@ram02z" }, +} + +list.php = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-php", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@tk-shirasaka" }, +} + +list.java = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-java", + files = { "src/parser.c" }, + }, + maintainers = { "@p00f" }, +} + +list.kotlin = { + install_info = { + url = "https://github.com/fwcd/tree-sitter-kotlin", + branch = "main", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@SalBakraa" }, +} + +list.html = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-html", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@TravonteD" }, +} + +list.julia = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-julia", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@theHamsta" }, +} + +list.json = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-json", + files = { "src/parser.c" }, + }, + maintainers = { "@steelsojka" }, +} + +list.jsonnet = { + install_info = { + url = "https://github.com/sourcegraph/tree-sitter-jsonnet", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@nawordar" }, +} + +list.css = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-css", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@TravonteD" }, +} + +list.scss = { + install_info = { + url = "https://github.com/serenadeai/tree-sitter-scss", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@elianiva" }, +} + +list.erlang = { + install_info = { + url = "https://github.com/WhatsApp/tree-sitter-erlang", + files = { "src/parser.c" }, + branch = "main", + }, + maintainers = { "@filmor" }, +} + +list.elixir = { + install_info = { + url = "https://github.com/elixir-lang/tree-sitter-elixir", + files = { "src/parser.c", "src/scanner.cc" }, + branch = "main", + }, + maintainers = { "@connorlay" }, +} + +list.gleam = { + install_info = { + url = "https://github.com/J3RN/tree-sitter-gleam", + files = { "src/parser.c" }, + branch = "main", + }, + maintainers = { "@connorlay" }, +} + +list.surface = { + install_info = { + url = "https://github.com/connorlay/tree-sitter-surface", + files = { "src/parser.c" }, + branch = "main", + }, + filetype = "sface", + maintainers = { "@connorlay" }, +} + +list.eex = { + install_info = { + url = "https://github.com/connorlay/tree-sitter-eex", + files = { "src/parser.c" }, + branch = "main", + }, + filetype = "eex", + maintainers = { "@connorlay" }, +} + +list.heex = { + install_info = { + url = "https://github.com/connorlay/tree-sitter-heex", + files = { "src/parser.c" }, + branch = "main", + }, + filetype = "heex", + maintainers = { "@connorlay" }, +} + +list.ocaml = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-ocaml", + files = { "src/parser.c", "src/scanner.cc" }, + location = "ocaml", + }, + maintainers = { "@undu" }, +} + +list.ocaml_interface = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-ocaml", + files = { "src/parser.c", "src/scanner.cc" }, + location = "interface", + }, + maintainers = { "@undu" }, + filetype = "ocamlinterface", +} + +list.ocamllex = { + install_info = { + url = "https://github.com/atom-ocaml/tree-sitter-ocamllex", + files = { "src/parser.c", "src/scanner.cc" }, + requires_generate_from_grammar = true, + }, + maintainers = { "@undu" }, +} + +list.menhir = { + install_info = { + url = "https://github.com/Kerl13/tree-sitter-menhir", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@Kerl13" }, + filetype = "menhir", +} + +list.org = { + install_info = { + url = "https://github.com/milisims/tree-sitter-org", + branch = "main", + files = { "src/parser.c", "src/scanner.cc" }, }, } + +list.swift = { + install_info = { + url = "https://github.com/alex-pinkus/tree-sitter-swift", + branch = "main", + files = { "src/parser.c", "src/scanner.c" }, + requires_generate_from_grammar = true, + }, + maintainers = { "@alex-pinkus" }, +} + +list.c_sharp = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-c-sharp", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "cs", + maintainers = { "@Luxed" }, +} + +list.todotxt = { + install_info = { + url = "https://github.com/arnarg/tree-sitter-todotxt.git", + files = { "src/parser.c" }, + branch = "main", + }, + filetype = "todotxt", + maintainers = { "@arnarg" }, + experimental = true, +} + +list.typescript = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-typescript", + files = { "src/parser.c", "src/scanner.c" }, + location = "typescript", + generate_requires_npm = true, + }, + maintainers = { "@steelsojka" }, +} + +list.tsx = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-typescript", + files = { "src/parser.c", "src/scanner.c" }, + location = "tsx", + generate_requires_npm = true, + }, + filetype = "typescriptreact", + maintainers = { "@steelsojka" }, +} + +list.scala = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-scala", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@stevanmilic" }, +} + +list.supercollider = { + install_info = { + url = "https://github.com/madskjeldgaard/tree-sitter-supercollider", + files = { "src/parser.c", "src/scanner.c" }, + branch = "main", + }, + maintainers = { "@madskjeldgaard" }, + filetype = "supercollider", +} + +list.slint = { + install_info = { + url = "https://github.com/jrmoulton/tree-sitter-slint", + files = { "src/parser.c" }, + branch = "main", + }, + maintainers = { "@jrmoulton" }, + experimental = true, +} + +list.haskell = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-haskell", + files = { "src/parser.c", "src/scanner.c" }, + }, +} + +list.hcl = { + install_info = { + url = "https://github.com/MichaHoffmann/tree-sitter-hcl", + files = { "src/parser.c", "src/scanner.cc" }, + branch = "main", + }, + maintainers = { "@MichaHoffmann" }, + filetype = "hcl", +} + +list.markdown = { + install_info = { + url = "https://github.com/MDeiml/tree-sitter-markdown", + location = "tree-sitter-markdown", + files = { "src/parser.c", "src/scanner.cc" }, + branch = "split_parser", + readme_name = "markdown (basic highlighting)", + }, + maintainers = { "@MDeiml" }, + experimental = true, +} + +list.markdown_inline = { + install_info = { + url = "https://github.com/MDeiml/tree-sitter-markdown", + location = "tree-sitter-markdown-inline", + files = { "src/parser.c", "src/scanner.cc" }, + branch = "split_parser", + readme_name = "markdown_inline (needs to be installed for full markdown highlighting)", + }, + maintainers = { "@MDeiml" }, + experimental = true, +} + +list.tlaplus = { + install_info = { + url = "https://github.com/tlaplus-community/tree-sitter-tlaplus", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@ahelwer", "@susliko" }, + filetype = "tla", +} + +list.toml = { + install_info = { + url = "https://github.com/ikatyang/tree-sitter-toml", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + maintainers = { "@tk-shirasaka" }, +} + +list.glimmer = { + install_info = { + url = "https://github.com/alexlafroscia/tree-sitter-glimmer", + files = { "src/parser.c", "src/scanner.c" }, + branch = "main", + }, + readme_name = "Glimmer and Ember", + maintainers = { "@NullVoxPopuli" }, + filetype = "handlebars", +} + +list.pug = { + install_info = { + url = "https://github.com/zealot128/tree-sitter-pug", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@zealot128" }, + filetype = "pug", + experimental = true, +} + +list.vue = { + install_info = { + url = "https://github.com/ikatyang/tree-sitter-vue", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@WhyNotHugo" }, +} + +list.jsonc = { + install_info = { + url = "https://gitlab.com/WhyNotHugo/tree-sitter-jsonc.git", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + readme_name = "JSON with comments", + maintainers = { "@WhyNotHugo" }, +} + +list.elm = { + install_info = { + url = "https://github.com/elm-tooling/tree-sitter-elm", + files = { "src/parser.c", "src/scanner.cc" }, + }, +} + +list.yaml = { + install_info = { + url = "https://github.com/ikatyang/tree-sitter-yaml", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@stsewd" }, +} + +list.yang = { + install_info = { + url = "https://github.com/Hubro/tree-sitter-yang", + files = { "src/parser.c" }, + }, + maintainers = { "@Hubro" }, + filetype = "yang", +} + +list.ninja = { + install_info = { + url = "https://github.com/alemuller/tree-sitter-ninja", + files = { "src/parser.c" }, + branch = "main", + }, + maintainers = { "@alemuller" }, +} + +list.nix = { + install_info = { + url = "https://github.com/cstrahan/tree-sitter-nix", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@leo60228" }, +} + +list.dart = { + install_info = { + url = "https://github.com/UserNobody14/tree-sitter-dart", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@akinsho" }, +} + +list.rst = { + install_info = { + url = "https://github.com/stsewd/tree-sitter-rst", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@stsewd" }, +} + +list.fennel = { + install_info = { + url = "https://github.com/travonted/tree-sitter-fennel", + files = { "src/parser.c" }, + }, + maintainers = { "@TravonteD" }, +} + +list.teal = { + install_info = { + url = "https://github.com/euclidianAce/tree-sitter-teal", + files = { "src/parser.c", "src/scanner.c" }, + requires_generate_from_grammar = true, + }, + maintainers = { "@euclidianAce" }, +} + +list.ql = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-ql", + files = { "src/parser.c" }, + }, + maintainers = { "@pwntester" }, +} + +list.verilog = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-verilog", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + maintainers = { "@zegervdv" }, +} + +list.pascal = { + install_info = { + url = "https://github.com/Isopod/tree-sitter-pascal.git", + files = { "src/parser.c" }, + }, + maintainers = { "@Isopod" }, +} + +-- Parsers for injections +list.phpdoc = { + install_info = { + url = "https://github.com/claytonrcarter/tree-sitter-phpdoc", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + maintainers = { "@mikehaertl" }, + experimental = true, +} + +list.regex = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-regex", + files = { "src/parser.c" }, + }, + maintainers = { "@theHamsta" }, +} + +list.comment = { + install_info = { + url = "https://github.com/stsewd/tree-sitter-comment", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@stsewd" }, +} + +list.jsdoc = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-jsdoc", + files = { "src/parser.c" }, + }, + maintainers = { "@steelsojka" }, +} + +list.query = { + install_info = { + url = "https://github.com/nvim-treesitter/tree-sitter-query", + files = { "src/parser.c" }, + }, + readme_name = "Tree-sitter query language", + maintainers = { "@steelsojka" }, +} + +list.sparql = { + install_info = { + url = "https://github.com/BonaBeavis/tree-sitter-sparql", + files = { "src/parser.c" }, + branch = "main", + }, + maintainers = { "@BonaBeavis" }, +} + +list.sql = { + install_info = { + url = "https://github.com/derekstride/tree-sitter-sql", + files = { "src/parser.c" }, + requires_generate_from_grammar = true, + }, + maintainers = { "@derekstride" }, +} + +list.gdscript = { + install_info = { + url = "https://github.com/PrestonKnopp/tree-sitter-gdscript", + files = { "src/parser.c", "src/scanner.cc" }, + }, + readme_name = "Godot (gdscript)", + maintainers = { "@Shatur" }, +} + +list.godot_resource = { + install_info = { + url = "https://github.com/PrestonKnopp/tree-sitter-godot-resource", + files = { "src/parser.c", "src/scanner.c" }, + requires_generate_from_grammar = true, + }, + filetype = "gdresource", + readme_name = "Godot Resources (gdresource)", + maintainers = { "@pierpo" }, +} + +list.turtle = { + install_info = { + url = "https://github.com/BonaBeavis/tree-sitter-turtle", + files = { "src/parser.c" }, + branch = "main", + }, + maintainers = { "@BonaBeavis" }, +} + +list.devicetree = { + install_info = { + url = "https://github.com/joelspadin/tree-sitter-devicetree", + files = { "src/parser.c" }, + branch = "main", + requires_generate_from_grammar = true, + }, + filetype = "dts", + maintainers = { "@jedrzejboczar" }, +} + +list.svelte = { + install_info = { + url = "https://github.com/Himujjal/tree-sitter-svelte", + files = { "src/parser.c", "src/scanner.c" }, + branch = "master", + }, + maintainers = { "@elianiva" }, +} + +list.r = { + install_info = { + url = "https://github.com/r-lib/tree-sitter-r", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@echasnovski" }, +} + +list.beancount = { + install_info = { + url = "https://github.com/polarmutex/tree-sitter-beancount", + files = { "src/parser.c", "src/scanner.cc" }, + branch = "master", + }, + maintainers = { "@polarmutex" }, +} + +list.rnoweb = { + install_info = { + url = "https://github.com/bamonroe/tree-sitter-rnoweb", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "rnoweb", + maintainers = { "@bamonroe" }, +} + +list.latex = { + install_info = { + url = "https://github.com/latex-lsp/tree-sitter-latex", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "tex", + maintainers = { "@theHamsta", "@clason" }, +} + +list.bibtex = { + install_info = { + url = "https://github.com/latex-lsp/tree-sitter-bibtex", + files = { "src/parser.c" }, + }, + filetype = "bib", + maintainers = { "@theHamsta", "@clason" }, +} + +list.zig = { + install_info = { + url = "https://github.com/maxxnino/tree-sitter-zig", + files = { "src/parser.c" }, + branch = "main", + }, + filetype = "zig", + maintainers = { "@maxxnino" }, +} + +list.fortran = { + install_info = { + url = "https://github.com/stadelmanma/tree-sitter-fortran", + files = { "src/parser.c", "src/scanner.cc" }, + }, +} + +list.cmake = { + install_info = { + url = "https://github.com/uyha/tree-sitter-cmake", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@uyha" }, +} + +list.vim = { + install_info = { + url = "https://github.com/vigoux/tree-sitter-viml", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "vim", + maintainers = { "@vigoux" }, +} + +list.help = { + install_info = { + url = "https://github.com/neovim/tree-sitter-vimdoc", + files = { "src/parser.c" }, + }, + filetype = "help", + maintainers = { "@vigoux" }, +} + +list.json5 = { + install_info = { + url = "https://github.com/Joakker/tree-sitter-json5", + files = { "src/parser.c" }, + }, + filetype = "json5", + maintainers = { "@Joakker" }, +} + +list.pioasm = { + install_info = { + url = "https://github.com/leo60228/tree-sitter-pioasm", + branch = "main", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@leo60228" }, +} + +list.hjson = { + install_info = { + url = "https://github.com/winston0410/tree-sitter-hjson", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + maintainers = { "@winston0410" }, +} + +list.hocon = { + install_info = { + url = "https://github.com/antosha417/tree-sitter-hocon", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + maintainers = { "@antosha417" }, +} + +list.llvm = { + install_info = { + url = "https://github.com/benwilliamgraham/tree-sitter-llvm", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@benwilliamgraham" }, +} + +list.http = { + install_info = { + url = "https://github.com/rest-nvim/tree-sitter-http", + branch = "main", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + maintainers = { "@NTBBloodbath" }, +} + +list.prisma = { + install_info = { + url = "https://github.com/victorhqc/tree-sitter-prisma", + branch = "master", + files = { "src/parser.c" }, + }, + maintainers = { "@elianiva" }, +} + +list.make = { + install_info = { + url = "https://github.com/alemuller/tree-sitter-make", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@lewis6991" }, +} + +list.rasi = { + install_info = { + url = "https://github.com/Fymyte/tree-sitter-rasi", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@Fymyte" }, +} + +list.foam = { + install_info = { + url = "https://github.com/FoamScience/tree-sitter-foam", + branch = "master", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@FoamScience" }, + filetype = "foam", + -- Queries might change over time on the grammar's side + -- Otherwise everything runs fine + experimental = true, +} + +list.hack = { + install_info = { + url = "https://github.com/slackhq/tree-sitter-hack", + branch = "main", + files = { "src/parser.c", "src/scanner.cc" }, + }, +} + +list.norg = { + install_info = { + url = "https://github.com/nvim-neorg/tree-sitter-norg", + branch = "main", + files = { "src/parser.c", "src/scanner.cc" }, + use_makefile = true, + cxx_standard = "c++14", + }, + maintainers = { "@JoeyGrajciar", "@vhyrro" }, +} + +list.vala = { + install_info = { + url = "https://github.com/vala-lang/tree-sitter-vala", + branch = "master", + files = { "src/parser.c" }, + }, + maintainers = { "@Prince781" }, +} + +list.lalrpop = { + install_info = { + url = "https://github.com/traxys/tree-sitter-lalrpop", + branch = "master", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@traxys" }, +} + +list.solidity = { + install_info = { + url = "https://github.com/YongJieYongJie/tree-sitter-solidity", + branch = "with-generated-c-code", + files = { "src/parser.c" }, + }, + maintainers = { "@YongJieYongJie" }, +} + +list.cooklang = { + install_info = { + url = "https://github.com/addcninblue/tree-sitter-cooklang", + branch = "master", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@addcninblue" }, +} + +list.elvish = { + install_info = { + url = "https://github.com/ckafi/tree-sitter-elvish", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@ckafi" }, +} + +list.astro = { + install_info = { + url = "https://github.com/virchau13/tree-sitter-astro", + branch = "master", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@virchau13" }, +} + +list.wgsl = { + install_info = { + url = "https://github.com/szebniok/tree-sitter-wgsl", + files = { "src/parser.c" }, + }, + maintainers = { "@szebniok" }, + filetype = "wgsl", +} + +list.m68k = { + install_info = { + url = "https://github.com/grahambates/tree-sitter-m68k", + files = { "src/parser.c" }, + }, + maintainers = { "@grahambates" }, + filetype = "asm68k", +} + +list.proto = { + install_info = { + url = "https://github.com/mitchellh/tree-sitter-proto", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@fsouza" }, + filetype = "proto", +} + +list.v = { + install_info = { + url = "https://github.com/vlang/vls", + files = { "src/parser.c", "src/scanner.c" }, + location = "tree_sitter_v", + generate_requires_npm = false, + requires_generate_from_grammar = false, + }, + filetype = "vlang", + maintainers = { "@kkharji" }, +} + +list.tiger = { + install_info = { + url = "https://github.com/ambroisie/tree-sitter-tiger", + files = { "src/parser.c", "src/scanner.c" }, + branch = "main", + generate_requires_npm = false, + requires_generate_from_grammar = false, + }, + filetype = "tiger", + maintainers = { "@ambroisie" }, +} + +list.sxhkdrc = { + install_info = { + url = "https://github.com/RaafatTurki/tree-sitter-sxhkdrc", + files = { "src/parser.c" }, + branch = "master", + generate_requires_npm = false, + requires_generate_from_grammar = false, + filetype = "sxhkdrc", + }, + maintainers = { "@RaafatTurki" }, +} + +list.gitignore = { + install_info = { + url = "https://github.com/shunsambongi/tree-sitter-gitignore", + files = { "src/parser.c" }, + branch = "main", + requires_generate_from_grammar = true, + }, + maintainers = { "@theHamsta" }, +} + +list.nickel = { + install_info = { + url = "https://github.com/nickel-lang/tree-sitter-nickel", + files = { "src/parser.c", "src/scanner.cc" }, + branch = "main", + }, +} + +list.gitattributes = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-gitattributes", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.git_rebase = { + install_info = { + url = "https://github.com/the-mikedavis/tree-sitter-git-rebase", + files = { "src/parser.c" }, + branch = "main", + }, + filetype = "gitrebase", + maintainers = { "@gbprod" }, +} + +list.gitcommit = { + install_info = { + url = "https://github.com/gbprod/tree-sitter-gitcommit", + files = { "src/parser.c", "src/scanner.c" }, + branch = "main", + }, + maintainers = { "@gbprod" }, +} + +list.blueprint = { + install_info = { + url = "https://gitlab.com/gabmus/tree-sitter-blueprint.git", + files = { "src/parser.c" }, + }, + maintainers = { "@gabmus" }, + experimental = true, +} + +list.twig = { + install_info = { + url = "https://github.com/gbprod/tree-sitter-twig", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@gbprod" }, + filetype = "twig", +} + +list.diff = { + install_info = { + url = "https://github.com/the-mikedavis/tree-sitter-diff", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@gbprod" }, + filetype = "gitdiff", +} + +list.vhs = { + install_info = { + url = "https://github.com/charmbracelet/tree-sitter-vhs", + branch = "main", + files = { "src/parser.c" }, + }, + maintainers = { "@caarlos0" }, + filetype = "tape", +} + +list.awk = { + install_info = { + url = "https://github.com/Beaglefoot/tree-sitter-awk", + files = { "src/parser.c", "src/scanner.c" }, + }, +} + +list.arduino = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-arduino", + files = { "src/parser.c", "src/scanner.cc" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.jq = { + install_info = { + url = "https://github.com/flurie/tree-sitter-jq", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.mermaid = { + install_info = { + url = "https://github.com/monaqa/tree-sitter-mermaid", + files = { "src/parser.c" }, + }, + experimental = true, +} + +list.ebnf = { + install_info = { + url = "https://github.com/RubixDev/ebnf.git", + files = { "src/parser.c" }, + location = "crates/tree-sitter-ebnf", + branch = "main", + }, + maintainers = { "@RubixDev" }, + experimental = true, +} + +local M = { + list = list, + filetype_to_parsername = filetype_to_parsername, +} + +function M.ft_to_lang(ft) + local result = filetype_to_parsername[ft] + if result then + return result + else + ft = vim.split(ft, ".", true)[1] + return filetype_to_parsername[ft] or ft + end +end + +function M.available_parsers() + if vim.fn.executable "tree-sitter" == 1 and vim.fn.executable "node" == 1 then + return vim.tbl_keys(M.list) + else + return vim.tbl_filter(function(p) + return not M.list[p].install_info.requires_generate_from_grammar + end, vim.tbl_keys(M.list)) + end +end + +function M.get_parser_configs() + return M.list +end + +local parser_files + +function M.reset_cache() + parser_files = setmetatable({}, { + __index = function(tbl, key) + rawset(tbl, key, api.nvim_get_runtime_file("parser/" .. key .. ".*", false)) + return rawget(tbl, key) + end, + }) +end + +M.reset_cache() + +function M.has_parser(lang) + lang = lang or M.get_buf_lang(api.nvim_get_current_buf()) + + if not lang or #lang == 0 then + return false + end + -- HACK: nvim internal API + if vim._ts_has_language(lang) then + return true + end + return #parser_files[lang] > 0 +end + +function M.get_parser(bufnr, lang) + bufnr = bufnr or api.nvim_get_current_buf() + lang = lang or M.get_buf_lang(bufnr) + + if M.has_parser(lang) then + return ts.get_parser(bufnr, lang) + end +end + +-- @deprecated This is only kept for legacy purposes. +-- All root nodes should be accounted for. +function M.get_tree_root(bufnr) + bufnr = bufnr or api.nvim_get_current_buf() + return M.get_parser(bufnr):parse()[1]:root() +end + +-- get language of given buffer +-- @param optional buffer number or current buffer +-- @returns language string of buffer +function M.get_buf_lang(bufnr) + bufnr = bufnr or api.nvim_get_current_buf() + return M.ft_to_lang(api.nvim_buf_get_option(bufnr, "ft")) +end + +return M diff --git a/lua/nvim-treesitter/query.lua b/lua/nvim-treesitter/query.lua new file mode 100644 index 000000000..bc80d51e6 --- /dev/null +++ b/lua/nvim-treesitter/query.lua @@ -0,0 +1,433 @@ +local api = vim.api +local tsq = require "vim.treesitter.query" +local tsrange = require "nvim-treesitter.tsrange" +local utils = require "nvim-treesitter.utils" +local parsers = require "nvim-treesitter.parsers" +local caching = require "nvim-treesitter.caching" + +local M = {} + +local EMPTY_ITER = function() end + +M.built_in_query_groups = { "highlights", "locals", "folds", "indents", "injections" } + +--- Creates a function that checks whether a given query exists +--- for a specific language. +---@param query string +---@return function(string): boolean +local function get_query_guard(query) + return function(lang) + return M.has_query_files(lang, query) + end +end + +for _, query in ipairs(M.built_in_query_groups) do + M["has_" .. query] = get_query_guard(query) +end + +---@return string[] +function M.available_query_groups() + local query_files = api.nvim_get_runtime_file("queries/*/*.scm", true) + local groups = {} + for _, f in ipairs(query_files) do + groups[vim.fn.fnamemodify(f, ":t:r")] = true + end + local list = {} + for k, _ in pairs(groups) do + table.insert(list, k) + end + return list +end + +do + local query_cache = caching.create_buffer_cache() + + local function update_cached_matches(bufnr, changed_tick, query_group) + query_cache.set(query_group, bufnr, { + tick = changed_tick, + cache = M.collect_group_results(bufnr, query_group) or {}, + }) + end + + function M.get_matches(bufnr, query_group) + bufnr = bufnr or api.nvim_get_current_buf() + local cached_local = query_cache.get(query_group, bufnr) + if not cached_local or api.nvim_buf_get_changedtick(bufnr) > cached_local.tick then + update_cached_matches(bufnr, api.nvim_buf_get_changedtick(bufnr), query_group) + end + + return query_cache.get(query_group, bufnr).cache + end +end + +---@param lang string +---@param query_name string +---@return string[] +local function runtime_queries(lang, query_name) + return api.nvim_get_runtime_file(string.format("queries/%s/%s.scm", lang, query_name), true) or {} +end + +---@type table> +local query_files_cache = {} + +---@param lang string +---@param query_name string +---@return boolean +function M.has_query_files(lang, query_name) + if not query_files_cache[lang] then + query_files_cache[lang] = {} + end + if query_files_cache[lang][query_name] == nil then + local files = runtime_queries(lang, query_name) + query_files_cache[lang][query_name] = files and #files > 0 + end + return query_files_cache[lang][query_name] +end + +do + local mt = {} + mt.__index = function(tbl, key) + if rawget(tbl, key) == nil then + rawset(tbl, key, {}) + end + return rawget(tbl, key) + end + + -- cache will auto set the table for each lang if it is nil + local cache = setmetatable({}, mt) + + --- Same as `vim.treesitter.query` except will return cached values + ---@param lang string + ---@param query_name string + function M.get_query(lang, query_name) + if cache[lang][query_name] == nil then + cache[lang][query_name] = tsq.get_query(lang, query_name) + end + + return cache[lang][query_name] + end + + --- Invalidates the query file cache. + --- If lang and query_name is both present, will reload for only the lang and query_name. + --- If only lang is present, will reload all query_names for that lang + --- If none are present, will reload everything + ---@param lang string + ---@param query_name string + function M.invalidate_query_cache(lang, query_name) + if lang and query_name then + cache[lang][query_name] = nil + if query_files_cache[lang] then + query_files_cache[lang][query_name] = nil + end + elseif lang and not query_name then + query_files_cache[lang] = nil + for query_name0, _ in pairs(cache[lang]) do + M.invalidate_query_cache(lang, query_name0) + end + elseif not lang and not query_name then + query_files_cache = {} + for lang0, _ in pairs(cache) do + for query_name0, _ in pairs(cache[lang0]) do + M.invalidate_query_cache(lang0, query_name0) + end + end + else + error "Cannot have query_name by itself!" + end + end +end + +--- This function is meant for an autocommand and not to be used. Only use if file is a query file. +---@param fname string +function M.invalidate_query_file(fname) + local fnamemodify = vim.fn.fnamemodify + M.invalidate_query_cache(fnamemodify(fname, ":p:h:t"), fnamemodify(fname, ":t:r")) +end + +---@class QueryInfo +---@field root LanguageTree +---@field source integer +---@field start integer +---@field stop integer + +---@param bufnr integer +---@param query_name string +---@param root LanguageTree +---@param root_lang string|nil +---@return Query|nil, QueryInfo|nil +local function prepare_query(bufnr, query_name, root, root_lang) + local buf_lang = parsers.get_buf_lang(bufnr) + + if not buf_lang then + return + end + + local parser = parsers.get_parser(bufnr, buf_lang) + if not parser then + return + end + + if not root then + local first_tree = parser:trees()[1] + + if first_tree then + root = first_tree:root() + end + end + + if not root then + return + end + + local range = { root:range() } + + if not root_lang then + local lang_tree = parser:language_for_range(range) + + if lang_tree then + root_lang = lang_tree:lang() + end + end + + if not root_lang then + return + end + + local query = M.get_query(root_lang, query_name) + if not query then + return + end + + return query, + { + root = root, + source = bufnr, + start = range[1], + -- The end row is exclusive so we need to add 1 to it. + stop = range[3] + 1, + } +end + +---@param query Query +---@param bufnr integer +---@param start_row integer +---@param end_row integer +function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row) + -- A function that splits a string on '.' + local function split(string) + local t = {} + for str in string.gmatch(string, "([^.]+)") do + table.insert(t, str) + end + + return t + end + -- Given a path (i.e. a List(String)) this functions inserts value at path + local function insert_to_path(object, path, value) + local curr_obj = object + + for index = 1, (#path - 1) do + if curr_obj[path[index]] == nil then + curr_obj[path[index]] = {} + end + + curr_obj = curr_obj[path[index]] + end + + curr_obj[path[#path]] = value + end + + local matches = query:iter_matches(qnode, bufnr, start_row, end_row) + + local function iterator() + local pattern, match, metadata = matches() + if pattern ~= nil then + local prepared_match = {} + + -- Extract capture names from each match + for id, node in pairs(match) do + local name = query.captures[id] -- name of the capture in the query + if name ~= nil then + local path = split(name .. ".node") + insert_to_path(prepared_match, path, node) + local metadata_path = split(name .. ".metadata") + insert_to_path(prepared_match, metadata_path, metadata[id]) + end + end + + -- Add some predicates for testing + local preds = query.info.patterns[pattern] + if preds then + for _, pred in pairs(preds) do + -- functions + if pred[1] == "set!" and type(pred[2]) == "string" then + insert_to_path(prepared_match, split(pred[2]), pred[3]) + end + if pred[1] == "make-range!" and type(pred[2]) == "string" and #pred == 4 then + insert_to_path( + prepared_match, + split(pred[2] .. ".node"), + tsrange.TSRange.from_nodes(bufnr, match[pred[3]], match[pred[4]]) + ) + end + end + end + + return prepared_match + end + end + return iterator +end + +--- Return all nodes corresponding to a specific capture path (like @definition.var, @reference.type) +---Works like M.get_references or M.get_scopes except you can choose the capture +---Can also be a nested capture like @definition.function to get all nodes defining a function. +--- +---@param bufnr integer the buffer +---@param captures string|string[] +---@param query_group string the name of query group (highlights or injections for example) +---@param root LanguageTree|nil node from where to start the search +---@param lang string|nil the language from where to get the captures. +--- Root nodes can have several languages. +---@return table|nil +function M.get_capture_matches(bufnr, captures, query_group, root, lang) + if type(captures) == "string" then + captures = { captures } + end + local strip_captures = {} + for i, capture in ipairs(captures) do + if capture:sub(1, 1) ~= "@" then + error 'Captures must start with "@"' + return + end + -- Remove leading "@". + strip_captures[i] = capture:sub(2) + end + + local matches = {} + for match in M.iter_group_results(bufnr, query_group, root, lang) do + for _, capture in ipairs(strip_captures) do + local insert = utils.get_at_path(match, capture) + if insert then + table.insert(matches, insert) + end + end + end + return matches +end + +function M.iter_captures(bufnr, query_name, root, lang) + local query, params = prepare_query(bufnr, query_name, root, lang) + if not query then + return EMPTY_ITER + end + assert(params) + + local iter = query:iter_captures(params.root, params.source, params.start, params.stop) + + local function wrapped_iter() + local id, node, metadata = iter() + if not id then + return + end + + local name = query.captures[id] + if string.sub(name, 1, 1) == "_" then + return wrapped_iter() + end + + return name, node, metadata + end + + return wrapped_iter +end + +function M.find_best_match(bufnr, capture_string, query_group, filter_predicate, scoring_function, root) + if string.sub(capture_string, 1, 1) == "@" then + --remove leading "@" + capture_string = string.sub(capture_string, 2) + end + + local best + local best_score + + for maybe_match in M.iter_group_results(bufnr, query_group, root) do + local match = utils.get_at_path(maybe_match, capture_string) + + if match and filter_predicate(match) then + local current_score = scoring_function(match) + if not best then + best = match + best_score = current_score + end + if current_score > best_score then + best = match + best_score = current_score + end + end + end + return best +end + +---Iterates matches from a query file. +---@param bufnr integer the buffer +---@param query_group string the query file to use +---@param root LanguageTree the root node +---@param root_lang string|nil the root node lang, if known +function M.iter_group_results(bufnr, query_group, root, root_lang) + local query, params = prepare_query(bufnr, query_group, root, root_lang) + if not query then + return EMPTY_ITER + end + assert(params) + + return M.iter_prepared_matches(query, params.root, params.source, params.start, params.stop) +end + +function M.collect_group_results(bufnr, query_group, root, lang) + local matches = {} + + for prepared_match in M.iter_group_results(bufnr, query_group, root, lang) do + table.insert(matches, prepared_match) + end + + return matches +end + +---@alias CaptureResFn function(string, LanguageTree, LanguageTree): string, string + +--- Same as get_capture_matches except this will recursively get matches for every language in the tree. +---@param bufnr integer The bufnr +---@param capture_or_fn string|CaptureResFn The capture to get. If a function is provided then that +--- function will be used to resolve both the capture and query argument. +--- The function can return `nil` to ignore that tree. +---@param query_type string The query to get the capture from. This is ignore if a function is provided +--- for the captuer argument. +function M.get_capture_matches_recursively(bufnr, capture_or_fn, query_type) + ---@type CaptureResFn + local type_fn + if type(capture_or_fn) == "function" then + type_fn = capture_or_fn + else + type_fn = function(_, _, _) + return capture_or_fn, query_type + end + end + local parser = parsers.get_parser(bufnr) + local matches = {} + + if parser then + parser:for_each_tree(function(tree, lang_tree) + local lang = lang_tree:lang() + local capture, type_ = type_fn(lang, tree, lang_tree) + + if capture then + vim.list_extend(matches, M.get_capture_matches(bufnr, capture, type_, tree:root(), lang)) + end + end) + end + + return matches +end + +return M diff --git a/lua/nvim-treesitter/query_predicates.lua b/lua/nvim-treesitter/query_predicates.lua new file mode 100644 index 000000000..0638b6e79 --- /dev/null +++ b/lua/nvim-treesitter/query_predicates.lua @@ -0,0 +1,188 @@ +local query = require "vim.treesitter.query" + +local function error(str) + vim.api.nvim_err_writeln(str) +end + +local function valid_args(name, pred, count, strict_count) + local arg_count = #pred - 1 + + if strict_count then + if arg_count ~= count then + error(string.format("%s must have exactly %d arguments", name, count)) + return false + end + elseif arg_count < count then + error(string.format("%s must have at least %d arguments", name, count)) + return false + end + + return true +end + +query.add_predicate("nth?", function(match, pattern, bufnr, pred) + if not valid_args("nth?", pred, 2, true) then + return + end + + local node = match[pred[2]] + local n = tonumber(pred[3]) + if node and node:parent() and node:parent():named_child_count() > n then + return node:parent():named_child(n) == node + end + + return false +end) + +local function has_ancestor(match, pattern, bufnr, pred) + if not valid_args(pred[1], pred, 2) then + return + end + + local node = match[pred[2]] + local ancestor_types = { unpack(pred, 3) } + if not node then + return true + end + + local just_direct_parent = pred[1]:find("has-parent", 1, true) + + node = node:parent() + while node do + if vim.tbl_contains(ancestor_types, node:type()) then + return true + end + if just_direct_parent then + node = nil + else + node = node:parent() + end + end + return false +end + +query.add_predicate("has-ancestor?", has_ancestor) + +query.add_predicate("has-parent?", has_ancestor) + +query.add_predicate("is?", function(match, pattern, bufnr, pred) + if not valid_args("is?", pred, 2) then + return + end + + -- Avoid circular dependencies + local locals = require "nvim-treesitter.locals" + local node = match[pred[2]] + local types = { unpack(pred, 3) } + + if not node then + return true + end + + local _, _, kind = locals.find_definition(node, bufnr) + + return vim.tbl_contains(types, kind) +end) + +query.add_predicate("has-type?", function(match, pattern, bufnr, pred) + if not valid_args(pred[1], pred, 2) then + return + end + + local node = match[pred[2]] + local types = { unpack(pred, 3) } + + if not node then + return true + end + + return vim.tbl_contains(types, node:type()) +end) + +-- Just avoid some annoying warnings for this directive +query.add_directive("make-range!", function() end) + +query.add_directive("downcase!", function(match, _, bufnr, pred, metadata) + local text, key, value + + if #pred == 3 then + -- (#downcase! @capture "key") + key = pred[3] + value = metadata[pred[2]][key] + else + -- (#downcase! "key") + key = pred[2] + value = metadata[key] + end + + if type(value) == "string" then + text = value + else + local node = match[value] + text = query.get_node_text(node, bufnr) or "" + end + + if #pred == 3 then + metadata[pred[2]][key] = string.lower(text) + else + metadata[key] = string.lower(text) + end +end) + +query.add_directive("exclude_children!", function(match, _pattern, _bufnr, pred, metadata) + local capture_id = pred[2] + local node = match[capture_id] + local start_row, start_col, end_row, end_col = node:range() + local ranges = {} + for i = 0, node:named_child_count() - 1 do + local child = node:named_child(i) + local child_start_row, child_start_col, child_end_row, child_end_col = child:range() + if child_start_row > start_row or child_start_col > start_col then + table.insert(ranges, { + start_row, + start_col, + child_start_row, + child_start_col, + }) + end + start_row = child_end_row + start_col = child_end_col + end + if end_row > start_row or end_col > start_col then + table.insert(ranges, { start_row, start_col, end_row, end_col }) + end + metadata.content = ranges +end) + +-- Trim blank lines from end of the region +-- Arguments are the captures to trim. +query.add_directive("trim!", function(match, _, bufnr, pred, metadata) + for _, id in ipairs { select(2, unpack(pred)) } do + local node = match[id] + local start_row, start_col, end_row, end_col = node:range() + + -- Don't trim if region ends in middle of a line + if end_col ~= 0 then + return + end + + while true do + -- As we only care when end_col == 0, always inspect one line above end_row. + local end_line = vim.api.nvim_buf_get_lines(bufnr, end_row - 1, end_row, true)[1] + + if end_line ~= "" then + break + end + + end_row = end_row - 1 + end + + -- If this produces an invalid range, we just skip it. + if start_row < end_row or (start_row == end_row and start_col <= end_col) then + if not metadata[id] then + metadata[id] = {} + end + metadata[id].range = { start_row, start_col, end_row, end_col } + end + end +end) diff --git a/lua/nvim-treesitter/shell_command_selectors.lua b/lua/nvim-treesitter/shell_command_selectors.lua new file mode 100644 index 000000000..59bbb0e41 --- /dev/null +++ b/lua/nvim-treesitter/shell_command_selectors.lua @@ -0,0 +1,270 @@ +local fn = vim.fn +local utils = require "nvim-treesitter.utils" + +local M = {} + +function M.select_mkdir_cmd(directory, cwd, info_msg) + if fn.has "win32" == 1 then + return { + cmd = "cmd", + opts = { + args = { "/C", "mkdir", directory }, + cwd = cwd, + }, + info = info_msg, + err = "Could not create " .. directory, + } + else + return { + cmd = "mkdir", + opts = { + args = { directory }, + cwd = cwd, + }, + info = info_msg, + err = "Could not create " .. directory, + } + end +end + +function M.select_rm_file_cmd(file, info_msg) + if fn.has "win32" == 1 then + return { + cmd = "cmd", + opts = { + args = { "/C", "if", "exist", file, "del", file }, + }, + info = info_msg, + err = "Could not delete " .. file, + } + else + return { + cmd = "rm", + opts = { + args = { file }, + }, + info = info_msg, + err = "Could not delete " .. file, + } + end +end + +---@return string|nil +function M.select_executable(executables) + return vim.tbl_filter(function(c) + return c ~= vim.NIL and fn.executable(c) == 1 + end, executables)[1] +end + +function M.select_compiler_args(repo, compiler) + if string.match(compiler, "cl$") or string.match(compiler, "cl.exe$") then + return { + "/Fe:", + "parser.so", + "/Isrc", + repo.files, + "-Os", + "/LD", + } + elseif string.match(compiler, "zig$") or string.match(compiler, "zig.exe$") then + return { + "c++", + "-o", + "parser.so", + repo.files, + "-lc", + "-Isrc", + "-shared", + "-Os", + } + else + local args = { + "-o", + "parser.so", + "-I./src", + repo.files, + "-shared", + "-Os", + "-lstdc++", + } + if fn.has "win32" == 0 then + table.insert(args, "-fPIC") + end + return args + end +end + +function M.select_compile_command(repo, cc, compile_location) + local make = M.select_executable { "gmake", "make" } + if + string.match(cc, "cl$") + or string.match(cc, "cl.exe$") + or not repo.use_makefile + or fn.has "win32" == 1 + or not make + then + return { + cmd = cc, + info = "Compiling...", + err = "Error during compilation", + opts = { + args = vim.tbl_flatten(M.select_compiler_args(repo, cc)), + cwd = compile_location, + }, + } + else + return { + cmd = make, + info = "Compiling...", + err = "Error during compilation", + opts = { + args = { + "--makefile=" .. utils.join_path(utils.get_package_path(), "scripts", "compile_parsers.makefile"), + "CC=" .. cc, + "CXX_STANDARD=" .. (repo.cxx_standard or "c++14"), + }, + cwd = compile_location, + }, + } + end +end + +function M.select_install_rm_cmd(cache_folder, project_name) + if fn.has "win32" == 1 then + local dir = cache_folder .. "\\" .. project_name + return { + cmd = "cmd", + opts = { + args = { "/C", "if", "exist", dir, "rmdir", "/s", "/q", dir }, + }, + } + else + return { + cmd = "rm", + opts = { + args = { "-rf", cache_folder .. "/" .. project_name }, + }, + } + end +end + +function M.select_mv_cmd(from, to, cwd) + if fn.has "win32" == 1 then + return { + cmd = "cmd", + opts = { + args = { "/C", "move", "/Y", from, to }, + cwd = cwd, + }, + } + else + return { + cmd = "mv", + opts = { + args = { from, to }, + cwd = cwd, + }, + } + end +end + +function M.select_download_commands(repo, project_name, cache_folder, revision, prefer_git) + local can_use_tar = vim.fn.executable "tar" == 1 and vim.fn.executable "curl" == 1 + local is_github = repo.url:find("github.com", 1, true) + local is_gitlab = repo.url:find("gitlab.com", 1, true) + + revision = revision or repo.branch or "master" + + if can_use_tar and (is_github or is_gitlab) and not prefer_git then + local path_sep = utils.get_path_sep() + local url = repo.url:gsub(".git$", "") + + local folder_rev = revision + if is_github and revision:match "^v%d" then + folder_rev = revision:sub(2) + end + + return { + M.select_install_rm_cmd(cache_folder, project_name .. "-tmp"), + { + cmd = "curl", + info = "Downloading " .. project_name .. "...", + err = "Error during download, please verify your internet connection", + opts = { + args = { + "--silent", + "-L", -- follow redirects + is_github and url .. "/archive/" .. revision .. ".tar.gz" + or url .. "/-/archive/" .. revision .. "/" .. project_name .. "-" .. revision .. ".tar.gz", + "--output", + project_name .. ".tar.gz", + }, + cwd = cache_folder, + }, + }, + M.select_mkdir_cmd(project_name .. "-tmp", cache_folder, "Creating temporary directory"), + { + cmd = "tar", + info = "Extracting " .. project_name .. "...", + err = "Error during tarball extraction.", + opts = { + args = { + "-xvzf", + project_name .. ".tar.gz", + "-C", + project_name .. "-tmp", + }, + cwd = cache_folder, + }, + }, + M.select_rm_file_cmd(cache_folder .. path_sep .. project_name .. ".tar.gz"), + M.select_mv_cmd( + utils.join_path(project_name .. "-tmp", url:match "[^/]-$" .. "-" .. folder_rev), + project_name, + cache_folder + ), + M.select_install_rm_cmd(cache_folder, project_name .. "-tmp"), + } + else + local git_folder = utils.join_path(cache_folder, project_name) + local clone_error = "Error during download, please verify your internet connection" + + return { + { + cmd = "git", + info = "Downloading " .. project_name .. "...", + err = clone_error, + opts = { + args = { + "clone", + repo.url, + project_name, + }, + cwd = cache_folder, + }, + }, + { + cmd = "git", + info = "Checking out locked revision", + err = "Error while checking out revision", + opts = { + args = { + "checkout", + revision, + }, + cwd = git_folder, + }, + }, + } + end +end + +function M.make_directory_change_for_command(dir, command) + if fn.has "win32" == 1 then + return string.format("pushd %s & %s & popd", dir, command) + else + return string.format("cd %s;\n %s", dir, command) + end +end + +return M diff --git a/lua/nvim-treesitter/statusline.lua b/lua/nvim-treesitter/statusline.lua new file mode 100644 index 000000000..cd75fcb00 --- /dev/null +++ b/lua/nvim-treesitter/statusline.lua @@ -0,0 +1,50 @@ +local parsers = require "nvim-treesitter.parsers" +local ts_utils = require "nvim-treesitter.ts_utils" + +local M = {} + +-- Trim spaces and opening brackets from end +local transform_line = function(line) + return line:gsub("%s*[%[%(%{]*%s*$", "") +end + +function M.statusline(opts) + if not parsers.has_parser() then + return + end + local options = opts or {} + if type(opts) == "number" then + options = { indicator_size = opts } + end + local bufnr = options.bufnr or 0 + local indicator_size = options.indicator_size or 100 + local type_patterns = options.type_patterns or { "class", "function", "method" } + local transform_fn = options.transform_fn or transform_line + local separator = options.separator or " -> " + + local current_node = ts_utils.get_node_at_cursor() + if not current_node then + return "" + end + + local lines = {} + local expr = current_node + + while expr do + local line = ts_utils._get_line_for_node(expr, type_patterns, transform_fn, bufnr) + if line ~= "" and not vim.tbl_contains(lines, line) then + table.insert(lines, 1, line) + end + expr = expr:parent() + end + + local text = table.concat(lines, separator) + local text_len = #text + if text_len > indicator_size then + return "..." .. text:sub(text_len - indicator_size, text_len) + end + + return text +end + +return M diff --git a/lua/nvim-treesitter/ts_utils.lua b/lua/nvim-treesitter/ts_utils.lua new file mode 100644 index 000000000..5994e4bcb --- /dev/null +++ b/lua/nvim-treesitter/ts_utils.lua @@ -0,0 +1,434 @@ +local api = vim.api + +local parsers = require "nvim-treesitter.parsers" +local utils = require "nvim-treesitter.utils" + +local M = {} + +local function get_node_text(node, bufnr) + bufnr = bufnr or api.nvim_get_current_buf() + if not node then + return {} + end + + -- We have to remember that end_col is end-exclusive + local start_row, start_col, end_row, end_col = M.get_node_range(node) + + if start_row ~= end_row then + local lines = api.nvim_buf_get_lines(bufnr, start_row, end_row + 1, false) + if next(lines) == nil then + return {} + end + lines[1] = string.sub(lines[1], start_col + 1) + -- end_row might be just after the last line. In this case the last line is not truncated. + if #lines == end_row - start_row + 1 then + lines[#lines] = string.sub(lines[#lines], 1, end_col) + end + return lines + else + local line = api.nvim_buf_get_lines(bufnr, start_row, start_row + 1, false)[1] + -- If line is nil then the line is empty + return line and { string.sub(line, start_col + 1, end_col) } or {} + end +end + +---@private +function M._get_line_for_node(node, type_patterns, transform_fn, bufnr) + local node_type = node:type() + local is_valid = false + for _, rgx in ipairs(type_patterns) do + if node_type:find(rgx) then + is_valid = true + break + end + end + if not is_valid then + return "" + end + local line = transform_fn(vim.trim(get_node_text(node, bufnr)[1] or "")) + -- Escape % to avoid statusline to evaluate content as expression + return line:gsub("%%", "%%%%") +end + +--- Gets the actual text content of a node +-- @deprecated Use vim.treesitter.query.get_node_text +-- @param node the node to get the text from +-- @param bufnr the buffer containing the node +-- @return list of lines of text of the node +function M.get_node_text(node, bufnr) + vim.notify_once( + "nvim-treesitter.ts_utils.get_node_text is deprecated: use vim.treesitter.query.get_node_text", + vim.log.levels.WARN + ) + return get_node_text(node, bufnr) +end + +--- Determines whether a node is the parent of another +-- @param dest the possible parent +-- @param source the possible child node +function M.is_parent(dest, source) + if not (dest and source) then + return false + end + + local current = source + while current ~= nil do + if current == dest then + return true + end + + current = current:parent() + end + + return false +end + +--- Get next node with same parent +-- @param node node +-- @param allow_switch_parents allow switching parents if last node +-- @param allow_next_parent allow next parent if last node and next parent without children +function M.get_next_node(node, allow_switch_parents, allow_next_parent) + local destination_node + local parent = node:parent() + + if not parent then + return + end + local found_pos = 0 + for i = 0, parent:named_child_count() - 1, 1 do + if parent:named_child(i) == node then + found_pos = i + break + end + end + if parent:named_child_count() > found_pos + 1 then + destination_node = parent:named_child(found_pos + 1) + elseif allow_switch_parents then + local next_node = M.get_next_node(node:parent()) + if next_node and next_node:named_child_count() > 0 then + destination_node = next_node:named_child(0) + elseif next_node and allow_next_parent then + destination_node = next_node + end + end + + return destination_node +end + +--- Get previous node with same parent +-- @param node node +-- @param allow_switch_parents allow switching parents if first node +-- @param allow_previous_parent allow previous parent if first node and previous parent without children +function M.get_previous_node(node, allow_switch_parents, allow_previous_parent) + local destination_node + local parent = node:parent() + if not parent then + return + end + + local found_pos = 0 + for i = 0, parent:named_child_count() - 1, 1 do + if parent:named_child(i) == node then + found_pos = i + break + end + end + if 0 < found_pos then + destination_node = parent:named_child(found_pos - 1) + elseif allow_switch_parents then + local previous_node = M.get_previous_node(node:parent()) + if previous_node and previous_node:named_child_count() > 0 then + destination_node = previous_node:named_child(previous_node:named_child_count() - 1) + elseif previous_node and allow_previous_parent then + destination_node = previous_node + end + end + return destination_node +end + +function M.get_named_children(node) + local nodes = {} + for i = 0, node:named_child_count() - 1, 1 do + nodes[i + 1] = node:named_child(i) + end + return nodes +end + +function M.get_node_at_cursor(winnr, ignore_injected_langs) + winnr = winnr or 0 + local cursor = api.nvim_win_get_cursor(winnr) + local cursor_range = { cursor[1] - 1, cursor[2] } + + local buf = vim.api.nvim_win_get_buf(winnr) + local root_lang_tree = parsers.get_parser(buf) + if not root_lang_tree then + return + end + + local root + if ignore_injected_langs then + for _, tree in ipairs(root_lang_tree:trees()) do + local tree_root = tree:root() + if tree_root and M.is_in_node_range(tree_root, cursor_range[1], cursor_range[2]) then + root = tree_root + break + end + end + else + root = M.get_root_for_position(cursor_range[1], cursor_range[2], root_lang_tree) + end + + if not root then + return + end + + return root:named_descendant_for_range(cursor_range[1], cursor_range[2], cursor_range[1], cursor_range[2]) +end + +function M.get_root_for_position(line, col, root_lang_tree) + if not root_lang_tree then + if not parsers.has_parser() then + return + end + + root_lang_tree = parsers.get_parser() + end + + local lang_tree = root_lang_tree:language_for_range { line, col, line, col } + + for _, tree in ipairs(lang_tree:trees()) do + local root = tree:root() + + if root and M.is_in_node_range(root, line, col) then + return root, tree, lang_tree + end + end + + -- This isn't a likely scenario, since the position must belong to a tree somewhere. + return nil, nil, lang_tree +end + +function M.get_root_for_node(node) + local parent = node + local result = node + + while parent ~= nil do + result = parent + parent = result:parent() + end + + return result +end + +function M.highlight_node(node, buf, hl_namespace, hl_group) + if not node then + return + end + M.highlight_range({ node:range() }, buf, hl_namespace, hl_group) +end + +--- Get a compatible vim range (1 index based) from a TS node range. +-- +-- TS nodes start with 0 and the end col is ending exclusive. +-- They also treat a EOF/EOL char as a char ending in the first +-- col of the next row. +function M.get_vim_range(range, buf) + local srow, scol, erow, ecol = unpack(range) + srow = srow + 1 + scol = scol + 1 + erow = erow + 1 + + if ecol == 0 then + -- Use the value of the last col of the previous row instead. + erow = erow - 1 + if not buf or buf == 0 then + ecol = vim.fn.col { erow, "$" } - 1 + else + ecol = #api.nvim_buf_get_lines(buf, erow - 1, erow, false)[1] + end + end + return srow, scol, erow, ecol +end + +function M.highlight_range(range, buf, hl_namespace, hl_group) + local start_row, start_col, end_row, end_col = unpack(range) + vim.highlight.range(buf, hl_namespace, hl_group, { start_row, start_col }, { end_row, end_col }) +end + +-- Set visual selection to node +-- @param selection_mode One of "charwise" (default) or "v", "linewise" or "V", +-- "blockwise" or "" (as a string with 5 characters or a single character) +function M.update_selection(buf, node, selection_mode) + selection_mode = selection_mode or "charwise" + local start_row, start_col, end_row, end_col = M.get_vim_range({ M.get_node_range(node) }, buf) + + -- Start visual selection in appropriate mode + local v_table = { charwise = "v", linewise = "V", blockwise = "" } + ---- Call to `nvim_replace_termcodes()` is needed for sending appropriate + ---- command to enter blockwise mode + local mode_string = vim.api.nvim_replace_termcodes(v_table[selection_mode] or selection_mode, true, true, true) + vim.cmd("normal! " .. mode_string) + vim.fn.setpos(".", { buf, start_row, start_col, 0 }) + vim.cmd "normal! o" + vim.fn.setpos(".", { buf, end_row, end_col, 0 }) +end + +-- Byte length of node range +function M.node_length(node) + local _, _, start_byte = node:start() + local _, _, end_byte = node:end_() + return end_byte - start_byte +end + +--- Determines whether (line, col) position is in node range +-- @param node Node defining the range +-- @param line A line (0-based) +-- @param col A column (0-based) +function M.is_in_node_range(node, line, col) + local start_line, start_col, end_line, end_col = node:range() + if line >= start_line and line <= end_line then + if line == start_line and line == end_line then + return col >= start_col and col < end_col + elseif line == start_line then + return col >= start_col + elseif line == end_line then + return col < end_col + else + return true + end + else + return false + end +end + +function M.get_node_range(node_or_range) + if type(node_or_range) == "table" then + return unpack(node_or_range) + else + return node_or_range:range() + end +end + +function M.node_to_lsp_range(node) + local start_line, start_col, end_line, end_col = M.get_node_range(node) + local rtn = {} + rtn.start = { line = start_line, character = start_col } + rtn["end"] = { line = end_line, character = end_col } + return rtn +end + +--- Memoizes a function based on the buffer tick of the provided bufnr. +-- The cache entry is cleared when the buffer is detached to avoid memory leaks. +-- @param fn: the fn to memoize, taking the bufnr as first argument +-- @param options: +-- - bufnr: extracts a bufnr from the given arguments. +-- - key: extracts the cache key from the given arguments. +-- @returns a memoized function +function M.memoize_by_buf_tick(fn, options) + options = options or {} + + local cache = {} + local bufnr_fn = utils.to_func(options.bufnr or utils.identity) + local key_fn = utils.to_func(options.key or utils.identity) + + return function(...) + local bufnr = bufnr_fn(...) + local key = key_fn(...) + local tick = api.nvim_buf_get_changedtick(bufnr) + + if cache[key] then + if cache[key].last_tick == tick then + return cache[key].result + end + else + local function detach_handler() + cache[key] = nil + end + + -- Clean up logic only! + api.nvim_buf_attach(bufnr, false, { + on_detach = detach_handler, + on_reload = detach_handler, + }) + end + + cache[key] = { + result = fn(...), + last_tick = tick, + } + + return cache[key].result + end +end + +function M.swap_nodes(node_or_range1, node_or_range2, bufnr, cursor_to_second) + if not node_or_range1 or not node_or_range2 then + return + end + local range1 = M.node_to_lsp_range(node_or_range1) + local range2 = M.node_to_lsp_range(node_or_range2) + + local text1 = get_node_text(node_or_range1, bufnr) + local text2 = get_node_text(node_or_range2, bufnr) + + local edit1 = { range = range1, newText = table.concat(text2, "\n") } + local edit2 = { range = range2, newText = table.concat(text1, "\n") } + vim.lsp.util.apply_text_edits({ edit1, edit2 }, bufnr, "utf-8") + + if cursor_to_second then + utils.set_jump() + + local char_delta = 0 + local line_delta = 0 + if + range1["end"].line < range2.start.line + or (range1["end"].line == range2.start.line and range1["end"].character < range2.start.character) + then + line_delta = #text2 - #text1 + end + + if range1["end"].line == range2.start.line and range1["end"].character < range2.start.character then + if line_delta ~= 0 then + --- why? + --correction_after_line_change = -range2.start.character + --text_now_before_range2 = #(text2[#text2]) + --space_between_ranges = range2.start.character - range1["end"].character + --char_delta = correction_after_line_change + text_now_before_range2 + space_between_ranges + --- Equivalent to: + char_delta = #text2[#text2] - range1["end"].character + + -- add range1.start.character if last line of range1 (now text2) does not start at 0 + if range1.start.line == range2.start.line + line_delta then + char_delta = char_delta + range1.start.character + end + else + char_delta = #text2[#text2] - #text1[#text1] + end + end + + api.nvim_win_set_cursor( + api.nvim_get_current_win(), + { range2.start.line + 1 + line_delta, range2.start.character + char_delta } + ) + end +end + +function M.goto_node(node, goto_end, avoid_set_jump) + if not node then + return + end + if not avoid_set_jump then + utils.set_jump() + end + local range = { M.get_vim_range { node:range() } } + local position + if not goto_end then + position = { range[1], range[2] } + else + position = { range[3], range[4] } + end + -- Position is 1, 0 indexed. + api.nvim_win_set_cursor(0, { position[1], position[2] - 1 }) +end + +return M diff --git a/lua/nvim-treesitter/tsrange.lua b/lua/nvim-treesitter/tsrange.lua new file mode 100644 index 000000000..d41585c60 --- /dev/null +++ b/lua/nvim-treesitter/tsrange.lua @@ -0,0 +1,154 @@ +local M = {} +local TSRange = {} +TSRange.__index = TSRange + +local api = vim.api +local ts_utils = require "nvim-treesitter.ts_utils" +local parsers = require "nvim-treesitter.parsers" + +local function get_byte_offset(buf, row, col) + return api.nvim_buf_get_offset(buf, row) + vim.fn.byteidx(api.nvim_buf_get_lines(buf, row, row + 1, false)[1], col) +end + +function TSRange.new(buf, start_row, start_col, end_row, end_col) + return setmetatable({ + start_pos = { start_row, start_col, get_byte_offset(buf, start_row, start_col) }, + end_pos = { end_row, end_col, get_byte_offset(buf, end_row, end_col) }, + buf = buf, + [1] = start_row, + [2] = start_col, + [3] = end_row, + [4] = end_col, + }, TSRange) +end + +function TSRange.from_nodes(buf, start_node, end_node) + TSRange.__index = TSRange + local start_pos = start_node and { start_node:start() } or { end_node:start() } + local end_pos = end_node and { end_node:end_() } or { start_node:end_() } + return setmetatable({ + start_pos = { start_pos[1], start_pos[2], start_pos[3] }, + end_pos = { end_pos[1], end_pos[2], end_pos[3] }, + buf = buf, + [1] = start_pos[1], + [2] = start_pos[2], + [3] = end_pos[1], + [4] = end_pos[2], + }, TSRange) +end + +function TSRange.from_table(buf, range) + return setmetatable({ + start_pos = { range[1], range[2], get_byte_offset(buf, range[1], range[2]) }, + end_pos = { range[3], range[4], get_byte_offset(buf, range[3], range[4]) }, + buf = buf, + [1] = range[1], + [2] = range[2], + [3] = range[3], + [4] = range[4], + }, TSRange) +end + +function TSRange:parent() + local root_lang_tree = parsers.get_parser(self.buf) + local root = ts_utils.get_root_for_position(self[1], self[2], root_lang_tree) + + return root + and root:named_descendant_for_range(self.start_pos[1], self.start_pos[2], self.end_pos[1], self.end_pos[2]) + or nil +end + +function TSRange:field() end + +function TSRange:child_count() + return #self:collect_children() +end + +function TSRange:named_child_count() + return #self:collect_children(function(c) + return c:named() + end) +end + +function TSRange:iter_children() + local raw_iterator = self:parent().iter_children() + return function() + while true do + local node = raw_iterator() + if not node then + return + end + local _, _, start_byte = node:start() + local _, _, end_byte = node:end_() + if start_byte >= self.start_pos[3] and end_byte <= self.end_pos[3] then + return node + end + end + end +end + +function TSRange:collect_children(filter_fun) + local children = {} + for _, c in self:iter_children() do + if not filter_fun or filter_fun(c) then + table.insert(children, c) + end + end + return children +end + +function TSRange:child(index) + return self:collect_children()[index + 1] +end + +function TSRange:named_child(index) + return self:collect_children(function(c) + return c.named() + end)[index + 1] +end + +function TSRange:start() + return unpack(self.start_pos) +end + +function TSRange:end_() + return unpack(self.end_pos) +end + +function TSRange:range() + return self.start_pos[1], self.start_pos[2], self.end_pos[1], self.end_pos[2] +end + +function TSRange:type() + return "nvim-treesitter-range" +end + +function TSRange:symbol() + return -1 +end + +function TSRange:named() + return false +end + +function TSRange:missing() + return false +end + +function TSRange:has_error() + return #self:collect_children(function(c) + return c:has_error() + end) > 0 and true or false +end + +function TSRange:sexpr() + return table.concat( + vim.tbl_map(function(c) + return c:sexpr() + end, self:collect_children()), + " " + ) +end + +M.TSRange = TSRange +return M diff --git a/lua/nvim-treesitter/util.lua b/lua/nvim-treesitter/util.lua deleted file mode 100644 index f2ff2f77f..000000000 --- a/lua/nvim-treesitter/util.lua +++ /dev/null @@ -1,20 +0,0 @@ -local M = {} - ---- @param filename string ---- @return string -function M.read_file(filename) - local file = assert(io.open(filename, 'r')) - local r = file:read('*a') - file:close() - return r -end - ---- @param filename string ---- @param content string -function M.write_file(filename, content) - local file = assert(io.open(filename, 'w')) - file:write(content) - file:close() -end - -return M diff --git a/lua/nvim-treesitter/utils.lua b/lua/nvim-treesitter/utils.lua new file mode 100644 index 000000000..156ba9c31 --- /dev/null +++ b/lua/nvim-treesitter/utils.lua @@ -0,0 +1,219 @@ +local api = vim.api +local fn = vim.fn +local luv = vim.loop + +local M = {} + +-- Wrapper around vim.notify with common options set. +function M.notify(msg, log_level, opts) + local default_opts = { title = "nvim-treesitter" } + vim.notify(msg, log_level, vim.tbl_extend("force", default_opts, opts or {})) +end + +-- Returns the system specific path seperator. +---@return string +function M.get_path_sep() + return fn.has "win32" == 1 and "\\" or "/" +end + +-- Returns a function that joins the given arguments with separator. Arguments +-- can't be nil. Example: +--[[ +print(M.generate_join(" ")("foo", "bar")) +--]] +-- prints "foo bar" +function M.generate_join(separator) + return function(...) + return table.concat({ ... }, separator) + end +end + +M.join_path = M.generate_join(M.get_path_sep()) + +M.join_space = M.generate_join " " + +--- Define user defined vim command which calls nvim-treesitter module function +--- - If module name is 'mod', it should be defined in hierarchy 'nvim-treesitter.mod' +--- - A table with name 'commands' should be defined in 'mod' which needs to be passed as +--- the commands param of this function +--- +---@param mod string, Name of the module that resides in the heirarchy - nvim-treesitter.module +---@param commands table, Command list for the module +--- - {command_name} Name of the vim user defined command, Keys: +--- - {run}: (function) callback function that needs to be executed +--- - {f_args}: (string, default ) +--- - type of arguments that needs to be passed to the vim command +--- - {args}: (string, optional) +--- - vim command attributes +--- +---Example: +--- If module is nvim-treesitter.custom_mod +---
+---  M.commands = {
+---      custom_command = {
+---          run = M.module_function,
+---          f_args = "",
+---          args = {
+---              "-range"
+---          }
+---      }
+---  }
+---
+---  utils.setup_commands("custom_mod", require("nvim-treesitter.custom_mod").commands)
+---  
+--- +--- Will generate command : +---
+---  command! -range custom_command \
+---      lua require'nvim-treesitter.custom_mod'.commands.custom_command['run']()
+---  
+function M.setup_commands(mod, commands) + for command_name, def in pairs(commands) do + local f_args = def.f_args or "" + local call_fn = + string.format("lua require'nvim-treesitter.%s'.commands.%s['run'](%s)", mod, command_name, f_args) + local parts = vim.tbl_flatten { + "command!", + "-bar", + def.args, + command_name, + call_fn, + } + api.nvim_command(table.concat(parts, " ")) + end +end + +---@param dir string +---@param create_err string +---@param writeable_err string +---@return string|nil, string|nil +function M.create_or_reuse_writable_dir(dir, create_err, writeable_err) + create_err = create_err or M.join_space("Could not create dir '", dir, "': ") + writeable_err = writeable_err or M.join_space("Invalid rights, '", dir, "' should be read/write") + -- Try creating and using parser_dir if it doesn't exist + if not luv.fs_stat(dir) then + local ok, error = pcall(vim.fn.mkdir, dir, "p", "0755") + if not ok then + return nil, M.join_space(create_err, error) + end + + return dir + end + + -- parser_dir exists, use it if it's read/write + if luv.fs_access(dir, "RW") then + return dir + end + + -- parser_dir exists but isn't read/write, give up + return nil, M.join_space(writeable_err, dir, "'") +end + +function M.get_package_path() + -- Path to this source file, removing the leading '@' + local source = string.sub(debug.getinfo(1, "S").source, 2) + + -- Path to the package root + return fn.fnamemodify(source, ":p:h:h:h") +end + +function M.get_cache_dir() + local cache_dir = fn.stdpath "data" + + if luv.fs_access(cache_dir, "RW") then + return cache_dir + elseif luv.fs_access("/tmp", "RW") then + return "/tmp" + end + + return nil, M.join_space("Invalid cache rights,", fn.stdpath "data", "or /tmp should be read/write") +end + +-- Returns $XDG_DATA_HOME/nvim/site, but could use any directory that is in +-- runtimepath +function M.get_site_dir() + return M.join_path(fn.stdpath "data", "site") +end + +-- Gets a property at path +-- @param tbl the table to access +-- @param path the '.' separated path +-- @returns the value at path or nil +function M.get_at_path(tbl, path) + if path == "" then + return tbl + end + local segments = vim.split(path, ".", true) + local result = tbl + + for _, segment in ipairs(segments) do + if type(result) == "table" then + result = result[segment] + end + end + + return result +end + +function M.set_jump() + vim.cmd "normal! m'" +end + +function M.index_of(tbl, obj) + for i, o in ipairs(tbl) do + if o == obj then + return i + end + end +end + +-- Filters a list based on the given predicate +-- @param tbl The list to filter +-- @param predicate The predicate to filter with +function M.filter(tbl, predicate) + local result = {} + + for i, v in ipairs(tbl) do + if predicate(v, i) then + table.insert(result, v) + end + end + + return result +end + +-- Returns a list of all values from the first list +-- that are not present in the second list. +-- @params tbl1 The first table +-- @params tbl2 The second table +function M.difference(tbl1, tbl2) + return M.filter(tbl1, function(v) + return not vim.tbl_contains(tbl2, v) + end) +end + +function M.identity(a) + return a +end + +function M.constant(a) + return function() + return a + end +end + +function M.to_func(a) + return type(a) == "function" and a or M.constant(a) +end + +---@return string|nil +function M.ts_cli_version() + if fn.executable "tree-sitter" == 1 then + local handle = io.popen "tree-sitter -V" + local result = handle:read "*a" + handle:close() + return vim.split(result, "\n")[1]:match "[^tree%psitter ].*" + end +end + +return M diff --git a/parser-info/.gitignore b/parser-info/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/parser-info/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/parser/.gitignore b/parser/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/parser/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/plugin/filetypes.lua b/plugin/filetypes.lua deleted file mode 100644 index f8fe0c287..000000000 --- a/plugin/filetypes.lua +++ /dev/null @@ -1,69 +0,0 @@ -local filetypes = { - angular = { 'htmlangular' }, - bash = { 'sh' }, - bibtex = { 'bib' }, - c_sharp = { 'cs', 'csharp' }, - commonlisp = { 'lisp' }, - cooklang = { 'cook' }, - devicetree = { 'dts' }, - diff = { 'gitdiff' }, - eex = { 'eelixir' }, - elixir = { 'ex' }, - embedded_template = { 'eruby' }, - erlang = { 'erl' }, - facility = { 'fsd' }, - faust = { 'dsp' }, - gdshader = { 'gdshaderinc' }, - git_config = { 'gitconfig' }, - git_rebase = { 'gitrebase' }, - glimmer = { 'handlebars', 'html.handlebars' }, - godot_resource = { 'gdresource' }, - haskell = { 'hs' }, - haskell_persistent = { 'haskellpersistent' }, - idris = { 'idris2' }, - ini = { 'confini', 'dosini' }, - janet_simple = { 'janet' }, - javascript = { 'javascriptreact', 'ecma', 'ecmascript', 'jsx', 'js' }, - json = { 'jsonc' }, - glimmer_javascript = { 'javascript.glimmer' }, - latex = { 'tex' }, - linkerscript = { 'ld' }, - m68k = { 'asm68k' }, - make = { 'automake' }, - markdown = { 'pandoc' }, - muttrc = { 'neomuttrc' }, - ocaml_interface = { 'ocamlinterface' }, - perl = { 'pl' }, - poe_filter = { 'poefilter' }, - powershell = { 'ps1' }, - properties = { 'jproperties' }, - python = { 'py', 'gyp' }, - qmljs = { 'qml' }, - runescript = { 'clientscript' }, - scala = { 'sbt' }, - slang = { 'shaderslang' }, - sqp = { 'mysqp' }, - ssh_config = { 'sshconfig' }, - starlark = { 'bzl' }, - surface = { 'sface' }, - systemverilog = { 'verilog' }, - t32 = { 'trace32' }, - tcl = { 'expect' }, - terraform = { 'terraform-vars' }, - textproto = { 'pbtxt' }, - tlaplus = { 'tla' }, - tsx = { 'typescriptreact', 'typescript.tsx' }, - typescript = { 'ts' }, - glimmer_typescript = { 'typescript.glimmer' }, - typst = { 'typ' }, - udev = { 'udevrules' }, - uxntal = { 'tal', 'uxn' }, - v = { 'vlang' }, - vhs = { 'tape' }, - xml = { 'xsd', 'xslt', 'svg' }, - xresources = { 'xdefaults' }, -} - -for lang, ft in pairs(filetypes) do - vim.treesitter.language.register(lang, ft) -end diff --git a/plugin/nvim-treesitter.lua b/plugin/nvim-treesitter.lua index adeb41425..4ea3925fd 100644 --- a/plugin/nvim-treesitter.lua +++ b/plugin/nvim-treesitter.lua @@ -1,75 +1,34 @@ +-- Last Change: 2022 Apr 16 + if vim.g.loaded_nvim_treesitter then return end vim.g.loaded_nvim_treesitter = true +-- setup modules +require("nvim-treesitter").setup() + local api = vim.api -local function complete_available_parsers(arglead) - return vim.tbl_filter( - --- @param v string - function(v) - return v:find(arglead) ~= nil - end, - require('nvim-treesitter.config').get_available() - ) -end +-- define autocommands +local augroup = api.nvim_create_augroup("NvimTreesitter", {}) -local function complete_installed_parsers(arglead) - return vim.tbl_filter( - --- @param v string - function(v) - return v:find(arglead) ~= nil - end, - require('nvim-treesitter.config').get_installed() - ) -end - --- create user commands -api.nvim_create_user_command('TSInstall', function(args) - require('nvim-treesitter.install').install(args.fargs, { force = args.bang, summary = true }) -end, { - nargs = '+', - bang = true, - bar = true, - complete = complete_available_parsers, - desc = 'Install treesitter parsers', -}) - -api.nvim_create_user_command('TSInstallFromGrammar', function(args) - require('nvim-treesitter.install').install(args.fargs, { - generate = true, - summary = true, - force = args.bang, - }) -end, { - nargs = '+', - bang = true, - bar = true, - complete = complete_available_parsers, - desc = 'Install treesitter parsers from grammar', -}) - -api.nvim_create_user_command('TSUpdate', function(args) - require('nvim-treesitter.install').update(args.fargs, { summary = true }) -end, { - nargs = '*', - bar = true, - complete = complete_installed_parsers, - desc = 'Update installed treesitter parsers', -}) - -api.nvim_create_user_command('TSUninstall', function(args) - require('nvim-treesitter.install').uninstall(args.fargs, { summary = true }) -end, { - nargs = '+', - bar = true, - complete = complete_installed_parsers, - desc = 'Uninstall treesitter parsers', -}) - -api.nvim_create_user_command('TSLog', function() - require('nvim-treesitter.log').show() -end, { - desc = 'View log messages', +api.nvim_create_autocmd("Filetype", { + pattern = "query", + group = augroup, + callback = function() + api.nvim_clear_autocmds { + group = augroup, + event = "BufWritePost", + } + api.nvim_create_autocmd("BufWritePost", { + group = augroup, + buffer = 0, + callback = function(opts) + require("nvim-treesitter.query").invalidate_query_file(opts.file) + end, + desc = "Invalidate query file", + }) + end, + desc = "Reload query", }) diff --git a/plugin/query_predicates.lua b/plugin/query_predicates.lua deleted file mode 100644 index 6511d3104..000000000 --- a/plugin/query_predicates.lua +++ /dev/null @@ -1,41 +0,0 @@ -local query = vim.treesitter.query - -local predicates = { - ---@param match table - ---@param pred any[] - ---@param any boolean - ---@return boolean - ['kind-eq'] = function(match, pred, any) - local nodes = match[pred[2]] - if not nodes or #nodes == 0 then - return true - end - - local types = { unpack(pred, 3) } - for _, node in ipairs(nodes) do - local res = vim.list_contains(types, node:type()) - if any and res then - return true - elseif not any and not res then - return false - end - end - return not any - end, -} - --- register custom predicates (overwrite existing; needed for CI) - ----@param match table ----@param pred any[] ----@return boolean -query.add_predicate('kind-eq?', function(match, _, _, pred) - return predicates['kind-eq'](match, pred, false) -end, { force = true }) - ----@param match table ----@param pred any[] ----@return boolean -query.add_predicate('any-kind-eq?', function(match, _, _, pred) - return predicates['kind-eq'](match, pred, true) -end, { force = true }) diff --git a/queries/agda/folds.scm b/queries/agda/folds.scm new file mode 100644 index 000000000..e3258efb9 --- /dev/null +++ b/queries/agda/folds.scm @@ -0,0 +1,4 @@ +[ + (record) + (module) +] @fold diff --git a/queries/agda/highlights.scm b/queries/agda/highlights.scm new file mode 100644 index 000000000..ed208f1b6 --- /dev/null +++ b/queries/agda/highlights.scm @@ -0,0 +1,82 @@ + +;; Constants +(integer) @number + +;; Variables and Symbols + +(typed_binding (atom (qid) @variable)) +(untyped_binding) @variable +(typed_binding (expr) @type) + +(id) @function +(bid) @function + +(function_name (atom (qid) @function)) +(field_name) @function + + +[(data_name) (record_name)] @constructor + +; Set +(SetN) @type.builtin + +(expr . (atom) @function) + +((atom) @boolean + (#any-of? @boolean "true" "false" "True" "False")) + +;; Imports and Module Declarations + +"import" @include + +(module_name) @namespace + +;; Pragmas and comments + +(pragma) @preproc + +(comment) @comment + +;; Keywords +[ + "where" + "data" + "rewrite" + "postulate" + "public" + "private" + "tactic" + "Prop" + "quote" + "renaming" + "open" + "in" + "hiding" + "constructor" + "abstract" + "let" + "field" + "mutual" + "module" + "infix" + "infixl" + "infixr" + "record" + (ARROW) +] +@keyword + +;;;(expr +;;; f_name: (atom) @function) +;; Brackets + +[ + "(" + ")" + "{" + "}"] +@punctuation.bracket + +[ + "=" +] @operator diff --git a/runtime/queries/arduino/folds.scm b/queries/arduino/folds.scm similarity index 100% rename from runtime/queries/arduino/folds.scm rename to queries/arduino/folds.scm diff --git a/queries/arduino/highlights.scm b/queries/arduino/highlights.scm new file mode 100644 index 000000000..a4e74ae89 --- /dev/null +++ b/queries/arduino/highlights.scm @@ -0,0 +1,111 @@ +; inherits: cpp + +((identifier) @function.builtin + (#any-of? @function.builtin + ; Digital I/O + "digitalRead" + "digitalWrite" + "pinMode" + ; Analog I/O + "analogRead" + "analogReference" + "analogWrite" + ; Zero, Due & MKR Family + "analogReadResolution" + "analogWriteResolution" + ; Advanced I/O + "noTone" + "pulseIn" + "pulseInLong" + "shiftIn" + "shiftOut" + "tone" + ; Time + "delay" + "delayMicroseconds" + "micros" + "millis" + ; Math + "abs" + "constrain" + "map" + "max" + "min" + "pow" + "sq" + "sqrt" + ; Trigonometry + "cos" + "sin" + "tan" + ; Characters + "isAlpha" + "isAlphaNumeric" + "isAscii" + "isControl" + "isDigit" + "isGraph" + "isHexadecimalDigit" + "isLowerCase" + "isPrintable" + "isPunct" + "isSpace" + "isUpperCase" + "isWhitespace" + ; Random Numbers + "random" + "randomSeed" + ; Bits and Bytes + "bit" + "bitClear" + "bitRead" + "bitSet" + "bitWrite" + "highByte" + "lowByte" + ; External Interrupts + "attachInterrupt" + "detachInterrupt" + ; Interrupts + "interrupts" + "noInterrupts" + )) + +((identifier) @type.builtin + (#any-of? @type.builtin + "Serial" + "SPI" + "Stream" + "Wire" + "Keyboard" + "Mouse" + "String" + )) + +((identifier) @constant.builtin + (#any-of? @constant.builtin + "HIGH" + "LOW" + "INPUT" + "OUTPUT" + "INPUT_PULLUP" + "LED_BUILTIN" + )) + +(function_definition + (function_declarator + declarator: (identifier) @function.builtin) + (#any-of? @function.builtin "loop" "setup")) + +(call_expression + function: (primitive_type) @function.builtin) + +(call_expression + function: (identifier) @constructor + (#any-of? @constructor "SPISettings" "String")) + +(declaration + (type_identifier) @type.builtin + (function_declarator + declarator: (identifier) @constructor) + (#eq? @type.builtin "SPISettings")) diff --git a/runtime/queries/arduino/indents.scm b/queries/arduino/indents.scm similarity index 100% rename from runtime/queries/arduino/indents.scm rename to queries/arduino/indents.scm diff --git a/queries/arduino/injections.scm b/queries/arduino/injections.scm new file mode 100644 index 000000000..ce1e7948a --- /dev/null +++ b/queries/arduino/injections.scm @@ -0,0 +1,3 @@ +(preproc_arg) @arduino + +(comment) @comment diff --git a/runtime/queries/arduino/locals.scm b/queries/arduino/locals.scm similarity index 100% rename from runtime/queries/arduino/locals.scm rename to queries/arduino/locals.scm diff --git a/runtime/queries/angular/folds.scm b/queries/astro/folds.scm similarity index 100% rename from runtime/queries/angular/folds.scm rename to queries/astro/folds.scm diff --git a/queries/astro/highlights.scm b/queries/astro/highlights.scm new file mode 100644 index 000000000..62e8ed247 --- /dev/null +++ b/queries/astro/highlights.scm @@ -0,0 +1,5 @@ +; inherits: html + +[ "---" ] @punctuation.delimiter + +[ "{" "}" ] @punctuation.special diff --git a/runtime/queries/astro/indents.scm b/queries/astro/indents.scm similarity index 100% rename from runtime/queries/astro/indents.scm rename to queries/astro/indents.scm diff --git a/queries/astro/injections.scm b/queries/astro/injections.scm new file mode 100644 index 000000000..95869e27c --- /dev/null +++ b/queries/astro/injections.scm @@ -0,0 +1,10 @@ +; inherits: html + +((frontmatter + (raw_text) @typescript)) + +((interpolation + (raw_text) @tsx)) + +((script_element + (raw_text) @typescript)) diff --git a/runtime/queries/angular/locals.scm b/queries/astro/locals.scm similarity index 100% rename from runtime/queries/angular/locals.scm rename to queries/astro/locals.scm diff --git a/queries/awk/highlights.scm b/queries/awk/highlights.scm new file mode 100644 index 000000000..a03c43670 --- /dev/null +++ b/queries/awk/highlights.scm @@ -0,0 +1,154 @@ +; adapted from https://github.com/Beaglefoot/tree-sitter-awk + +[ + (identifier) + (field_ref) +] @variable +(field_ref (_) @variable) + +(number) @number + +(string) @string +(regex) @string.regex +(escape_sequence) @string.escape + +(comment) @comment @spell + +(ns_qualified_name (namespace) @namespace) +(ns_qualified_name "::" @punctuation.delimiter) + +(func_def name: (_ (identifier) @function) @function) +(func_call name: (_ (identifier) @function) @function) + +(func_def (param_list (identifier) @parameter)) + +[ + "print" + "printf" + "getline" +] @function.builtin + +[ + (delete_statement) + (break_statement) + (continue_statement) + (next_statement) + (nextfile_statement) +] @keyword + +[ + "func" + "function" +] @keyword.function + +[ + "return" + "exit" +] @keyword.return + +[ + "do" + "while" + "for" + "in" +] @repeat + +[ + "if" + "else" + "switch" + "case" + "default" +] @conditional + +[ + "@include" + "@load" +] @include + +"@namespace" @preproc + +[ + "BEGIN" + "END" + "BEGINFILE" + "ENDFILE" +] @label + +(binary_exp [ + "^" + "**" + "*" + "/" + "%" + "+" + "-" + "<" + ">" + "<=" + ">=" + "==" + "!=" + "~" + "!~" + "in" + "&&" + "||" +] @operator) + +(unary_exp [ + "!" + "+" + "-" +] @operator) + +(assignment_exp [ + "=" + "+=" + "-=" + "*=" + "/=" + "%=" + "^=" +] @operator) + +(ternary_exp [ + "?" + ":" +] @conditional.ternary) + +(update_exp [ + "++" + "--" +] @operator) + +(redirected_io_statement [ + ">" + ">>" +] @operator) + +(piped_io_statement [ + "|" + "|&" +] @operator) + +(piped_io_exp [ + "|" + "|&" +] @operator) + +(field_ref "$" @punctuation.delimiter) + +(regex "/" @punctuation.delimiter) +(regex_constant "@" @punctuation.delimiter) + +[ ";" "," ] @punctuation.delimiter + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket diff --git a/queries/awk/injections.scm b/queries/awk/injections.scm new file mode 100644 index 000000000..8cbffc623 --- /dev/null +++ b/queries/awk/injections.scm @@ -0,0 +1,2 @@ +(comment) @comment +(regex) @regex diff --git a/runtime/queries/bash/folds.scm b/queries/bash/folds.scm similarity index 86% rename from runtime/queries/bash/folds.scm rename to queries/bash/folds.scm index 766dbe598..851c67eed 100644 --- a/runtime/queries/bash/folds.scm +++ b/queries/bash/folds.scm @@ -5,5 +5,4 @@ (for_statement) (while_statement) (c_style_for_statement) - (heredoc_redirect) ] @fold diff --git a/queries/bash/highlights.scm b/queries/bash/highlights.scm new file mode 100644 index 000000000..d1cdb659d --- /dev/null +++ b/queries/bash/highlights.scm @@ -0,0 +1,136 @@ +(simple_expansion) @none +(expansion + "${" @punctuation.special + "}" @punctuation.special) @none +[ + "(" + ")" + "((" + "))" + "{" + "}" + "[" + "]" + "[[" + "]]" + ] @punctuation.bracket + +[ + ";" + ";;" + (heredoc_start) + ] @punctuation.delimiter + +[ + "$" +] @punctuation.special + +[ + ">" + ">>" + "<" + "<<" + "&" + "&&" + "|" + "||" + "=" + "=~" + "==" + "!=" + ] @operator + +[ + (string) + (raw_string) + (ansi_c_string) + (heredoc_body) +] @string @spell + +(variable_assignment (word) @string) + +[ + "if" + "then" + "else" + "elif" + "fi" + "case" + "in" + "esac" + ] @conditional + +[ + "for" + "do" + "done" + "while" + ] @repeat + +[ + "declare" + "export" + "local" + "readonly" + "unset" + ] @keyword + +"function" @keyword.function + +(special_variable_name) @constant + +; trap -l +((word) @constant.builtin + (#match? @constant.builtin "^SIG(HUP|INT|QUIT|ILL|TRAP|ABRT|BUS|FPE|KILL|USR[12]|SEGV|PIPE|ALRM|TERM|STKFLT|CHLD|CONT|STOP|TSTP|TT(IN|OU)|URG|XCPU|XFSZ|VTALRM|PROF|WINCH|IO|PWR|SYS|RTMIN([+]([1-9]|1[0-5]))?|RTMAX(-([1-9]|1[0-4]))?)$")) + +((word) @boolean + (#match? @boolean "^(true|false)$")) + +(comment) @comment @spell +(test_operator) @string + +(command_substitution + [ "$(" ")" ] @punctuation.bracket) + +(process_substitution + [ "<(" ")" ] @punctuation.bracket) + + +(function_definition + name: (word) @function) + +(command_name (word) @function.call) + +((command_name (word) @function.builtin) + (#any-of? @function.builtin + "alias" "cd" "clear" "echo" "eval" "exit" "getopts" "popd" + "pushd" "return" "set" "shift" "shopt" "source" "test")) + +(command + argument: [ + (word) @parameter + (concatenation (word) @parameter) + ]) + +((word) @number + (#lua-match? @number "^[0-9]+$")) + +(file_redirect + descriptor: (file_descriptor) @operator + destination: (word) @parameter) + +(expansion + [ "${" "}" ] @punctuation.bracket) + +(variable_name) @variable + +((variable_name) @constant + (#lua-match? @constant "^[A-Z][A-Z_0-9]*$")) + +(case_item + value: (word) @parameter) + +(regex) @string.regex + +((program . (comment) @preproc) + (#match? @preproc "^#!/")) diff --git a/queries/bash/injections.scm b/queries/bash/injections.scm new file mode 100644 index 000000000..86371b905 --- /dev/null +++ b/queries/bash/injections.scm @@ -0,0 +1,3 @@ +(comment) @comment + +(regex) @regex diff --git a/queries/bash/locals.scm b/queries/bash/locals.scm new file mode 100644 index 000000000..a03bc3a56 --- /dev/null +++ b/queries/bash/locals.scm @@ -0,0 +1,13 @@ +; Scopes +(function_definition) @scope + +; Definitions +(variable_assignment + name: (variable_name) @definition.var) + +(function_definition + name: (word) @definition.function) + +; References +(variable_name) @reference +(word) @reference diff --git a/queries/beancount/folds.scm b/queries/beancount/folds.scm new file mode 100644 index 000000000..ffe319500 --- /dev/null +++ b/queries/beancount/folds.scm @@ -0,0 +1,4 @@ +[ + (transaction) + (section) +] @fold diff --git a/queries/beancount/highlights.scm b/queries/beancount/highlights.scm new file mode 100644 index 000000000..7fa78d84e --- /dev/null +++ b/queries/beancount/highlights.scm @@ -0,0 +1,26 @@ + +(date) @field +(txn) @attribute + +(account) @type + +(amount) @number +(incomplete_amount) @number +(amount_tolerance) @number + +(currency) @property + +(key) @label +(string) @string + +(tag) @constant +(link) @constant + +(comment) @comment + +[ + (balance) (open) (close) (commodity) (pad) + (event) (price) (note) (document) (query) + (custom) (pushtag) (poptag) (pushmeta) + (popmeta) (option) (include) (plugin) +] @keyword diff --git a/queries/bibtex/folds.scm b/queries/bibtex/folds.scm new file mode 100644 index 000000000..3b24d5fea --- /dev/null +++ b/queries/bibtex/folds.scm @@ -0,0 +1,3 @@ +[ + (entry) +] @fold diff --git a/runtime/queries/bibtex/highlights.scm b/queries/bibtex/highlights.scm similarity index 65% rename from runtime/queries/bibtex/highlights.scm rename to queries/bibtex/highlights.scm index 2231a17db..00cae314d 100644 --- a/runtime/queries/bibtex/highlights.scm +++ b/queries/bibtex/highlights.scm @@ -1,4 +1,5 @@ ; CREDITS @pfoerster (adapted from https://github.com/latex-lsp/tree-sitter-bibtex) + [ (string_type) (preamble_type) @@ -10,8 +11,6 @@ (comment) ] @comment -(comment) @spell - [ "=" "#" @@ -22,27 +21,20 @@ (number) @number (field - name: (identifier) @property) + name: (identifier) @field) (token - (identifier) @variable.parameter) + (identifier) @parameter) [ (brace_word) (quote_word) ] @string -((field - name: (identifier) @_url - value: (value - (token - (brace_word) @string.special.url))) - (#any-of? @_url "url" "doi")) - [ (key_brace) (key_paren) -] @markup.link.label +] @symbol (string name: (identifier) @constant) diff --git a/queries/bibtex/indents.scm b/queries/bibtex/indents.scm new file mode 100644 index 000000000..af652160e --- /dev/null +++ b/queries/bibtex/indents.scm @@ -0,0 +1,10 @@ +[ + (entry) +] @indent + +[ + "{" + "}" +] @branch + +(comment) @ignore diff --git a/queries/blueprint/highlights.scm b/queries/blueprint/highlights.scm new file mode 100644 index 000000000..3d4b48266 --- /dev/null +++ b/queries/blueprint/highlights.scm @@ -0,0 +1,57 @@ +(object_id) @variable + +(string) @string +(escape_sequence) @string.escape + +(comment) @comment + +(constant) @constant.builtin + +(boolean) @boolean + +(using) @include + +(template) @keyword + +(decorator) @attribute + +(property_definition (property_name) @property) + +(object) @type + +(signal_binding (signal_name) @function.builtin) +(signal_binding (function (identifier)) @function) +(signal_binding "swapped" @keyword) + +(styles_list "styles" @function.macro) +(layout_definition "layout" @function.macro) + +(gettext_string "_" @function.builtin) + +(menu_definition "menu" @keyword) +(menu_section "section" @keyword) +(menu_item "item" @function.macro) + +(template_definition (template_name_qualifier) @type.qualifier) + +(import_statement (gobject_library) @namespace) + +(import_statement (version_number) @float) + +(float) @float +(number) @number + +[ + ";" + "." + "," +] @punctuation.delimiter + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket diff --git a/queries/c/folds.scm b/queries/c/folds.scm new file mode 100644 index 000000000..80c3039b6 --- /dev/null +++ b/queries/c/folds.scm @@ -0,0 +1,19 @@ +[ + (for_statement) + (if_statement) + (while_statement) + (switch_statement) + (case_statement) + (function_definition) + (struct_specifier) + (enum_specifier) + (comment) + (preproc_if) + (preproc_elif) + (preproc_else) + (preproc_ifdef) + (initializer_list) +] @fold + + (compound_statement + (compound_statement) @fold) diff --git a/queries/c/highlights.scm b/queries/c/highlights.scm new file mode 100644 index 000000000..f1cff7467 --- /dev/null +++ b/queries/c/highlights.scm @@ -0,0 +1,199 @@ +; Lower priority to prefer @parameter when identifier appears in parameter_declaration. +((identifier) @variable (#set! "priority" 95)) + +[ + "default" + "enum" + "struct" + "typedef" + "union" + "goto" +] @keyword + +"sizeof" @keyword.operator + +"return" @keyword.return + +[ + "while" + "for" + "do" + "continue" + "break" +] @repeat + +[ + "if" + "else" + "case" + "switch" +] @conditional + +[ + "#if" + "#ifdef" + "#ifndef" + "#else" + "#elif" + "#endif" + (preproc_directive) +] @preproc + +"#define" @define + +"#include" @include + +[ ";" ":" "," ] @punctuation.delimiter + +"..." @punctuation.special + +[ "(" ")" "[" "]" "{" "}"] @punctuation.bracket + +[ + "=" + + "-" + "*" + "/" + "+" + "%" + + "~" + "|" + "&" + "^" + "<<" + ">>" + + "->" + "." + + "<" + "<=" + ">=" + ">" + "==" + "!=" + + "!" + "&&" + "||" + + "-=" + "+=" + "*=" + "/=" + "%=" + "|=" + "&=" + "^=" + ">>=" + "<<=" + "--" + "++" +] @operator + +;; Make sure the comma operator is given a highlight group after the comma +;; punctuator so the operator is highlighted properly. +(comma_expression [ "," ] @operator) + +[ + (true) + (false) +] @boolean + +(conditional_expression [ "?" ":" ] @conditional.ternary) + +(string_literal) @string +(system_lib_string) @string +(escape_sequence) @string.escape + +(null) @constant.builtin +(number_literal) @number +(char_literal) @character + +[ + (preproc_arg) + (preproc_defined) +] @function.macro + +(((field_expression + (field_identifier) @property)) @_parent + (#not-has-parent? @_parent template_method function_declarator call_expression)) + +(field_designator) @property +(((field_identifier) @property) + (#has-ancestor? @property field_declaration) + (#not-has-ancestor? @property function_declarator)) + +(statement_identifier) @label + +[ + (type_identifier) + (sized_type_specifier) + (type_descriptor) +] @type + +(storage_class_specifier) @storageclass + +(type_qualifier) @type.qualifier + +(type_definition + declarator: (type_identifier) @type.definition) + +(primitive_type) @type.builtin + +((identifier) @constant + (#lua-match? @constant "^[A-Z][A-Z0-9_]+$")) +(enumerator + name: (identifier) @constant) +(case_statement + value: (identifier) @constant) + +((identifier) @constant.builtin + (#any-of? @constant.builtin "stderr" "stdin" "stdout")) + +;; Preproc def / undef +(preproc_def + name: (_) @constant) +(preproc_call + directive: (preproc_directive) @_u + argument: (_) @constant + (#eq? @_u "#undef")) + +(call_expression + function: (identifier) @function.call) +(call_expression + function: (field_expression + field: (field_identifier) @function.call)) +(function_declarator + declarator: (identifier) @function) +(preproc_function_def + name: (identifier) @function.macro) + +(comment) @comment @spell + +;; Parameters +(parameter_declaration + declarator: (identifier) @parameter) + +(parameter_declaration + declarator: (pointer_declarator) @parameter) + +(preproc_params (identifier) @parameter) + +[ + "__attribute__" + "__cdecl" + "__clrcall" + "__stdcall" + "__fastcall" + "__thiscall" + "__vectorcall" + "_unaligned" + "__unaligned" + "__declspec" + (attribute_declaration) +] @attribute + +(ERROR) @error diff --git a/queries/c/indents.scm b/queries/c/indents.scm new file mode 100644 index 000000000..1931471b9 --- /dev/null +++ b/queries/c/indents.scm @@ -0,0 +1,49 @@ +[ + (compound_statement) + (preproc_arg) + (field_declaration_list) + (case_statement) + (enumerator_list) + (struct_specifier) + (compound_literal_expression) + (initializer_list) + (while_statement) + (for_statement) + (switch_statement) + (expression_statement) +] @indent +(if_statement condition: (_) @indent) +((if_statement + consequence: (_) @_consequence + (#not-has-type? @_consequence compound_statement) + ) @indent) +(init_declarator) @indent + +(compound_statement "}" @indent_end) + +[ + "else" + ")" + "}" + (statement_identifier) +] @branch + +[ + "#define" + "#ifdef" + "#if" + "#else" + "#endif" +] @zero_indent + +[ + (preproc_arg) + (string_literal) +] @ignore + +((ERROR (parameter_declaration)) @aligned_indent + (#set! "delimiter" "()")) +([(argument_list) (parameter_list)] @aligned_indent + (#set! "delimiter" "()")) + +(comment) @auto diff --git a/queries/c/injections.scm b/queries/c/injections.scm new file mode 100644 index 000000000..afeb068a2 --- /dev/null +++ b/queries/c/injections.scm @@ -0,0 +1,3 @@ +(preproc_arg) @c + +(comment) @comment diff --git a/queries/c/locals.scm b/queries/c/locals.scm new file mode 100644 index 000000000..78a2180d3 --- /dev/null +++ b/queries/c/locals.scm @@ -0,0 +1,53 @@ +;; Functions definitions +(function_declarator + declarator: (identifier) @definition.function) +(preproc_function_def + name: (identifier) @definition.macro) @scope + +(preproc_def + name: (identifier) @definition.macro) +(pointer_declarator + declarator: (identifier) @definition.var) +(parameter_declaration + declarator: (identifier) @definition.parameter) +(init_declarator + declarator: (identifier) @definition.var) +(array_declarator + declarator: (identifier) @definition.var) +(declaration + declarator: (identifier) @definition.var) +(enum_specifier + name: (_) @definition.type + (enumerator_list + (enumerator name: (identifier) @definition.var))) + +;; Type / Struct / Enum +(field_declaration + declarator: (field_identifier) @definition.field) +(type_definition + declarator: (type_identifier) @definition.type) +(struct_specifier + name: (type_identifier) @definition.type) + +;; goto +(labeled_statement (statement_identifier) @definition) + +;; References +(identifier) @reference +((field_identifier) @reference + (set! reference.kind "field")) +((type_identifier) @reference + (set! reference.kind "type")) + +(goto_statement (statement_identifier) @reference) + +;; Scope +[ + (for_statement) + (if_statement) + (while_statement) + (translation_unit) + (function_definition) + (compound_statement) ; a block in curly braces + (struct_specifier) +] @scope diff --git a/queries/c_sharp/folds.scm b/queries/c_sharp/folds.scm new file mode 100644 index 000000000..4b5d94270 --- /dev/null +++ b/queries/c_sharp/folds.scm @@ -0,0 +1,15 @@ +body: [ + (declaration_list) + (switch_body) + (enum_member_declaration_list) +] @fold + +accessors: [ + (accessor_list) +] @fold + +initializer: [ + (initializer_expression) +] @fold + +(block) @fold diff --git a/queries/c_sharp/highlights.scm b/queries/c_sharp/highlights.scm new file mode 100644 index 000000000..3ecdffb6e --- /dev/null +++ b/queries/c_sharp/highlights.scm @@ -0,0 +1,399 @@ +(identifier) @variable + +((identifier) @keyword + (#eq? @keyword "value") + (#has-ancestor? @keyword accessor_declaration)) + +(method_declaration + name: (identifier) @method) + +(local_function_statement + name: (identifier) @method) + +(method_declaration + type: (identifier) @type) + +(local_function_statement + type: (identifier) @type) + +(interpolation) @none + +(invocation_expression + (member_access_expression + name: (identifier) @method.call)) + +(invocation_expression + function: (conditional_access_expression + (member_binding_expression + name: (identifier) @method.call))) + +(namespace_declaration + name: [(qualified_name) (identifier)] @namespace) + +(qualified_name + (identifier) @type) + +(invocation_expression + (identifier) @method.call) + +(field_declaration + (variable_declaration + (variable_declarator + (identifier) @field))) + +(initializer_expression + (assignment_expression + left: (identifier) @field)) + +(parameter_list + (parameter + name: (identifier) @parameter)) + +(parameter_list + (parameter + type: (identifier) @type)) + +(integer_literal) @number +(real_literal) @float + +(null_literal) @constant.builtin +(character_literal) @character + +[ + (string_literal) + (verbatim_string_literal) + (interpolated_string_expression) +] @string + +(boolean_literal) @boolean + +[ + (predefined_type) + (void_keyword) +] @type.builtin + +(implicit_type) @keyword + +(comment) @comment @spell + +(using_directive + (identifier) @type) + +(using_directive + (name_equals (identifier) @type.definition)) + +(property_declaration + name: (identifier) @property) + +(property_declaration + type: (identifier) @type) + +(nullable_type + (identifier) @type) + +(catch_declaration + type: (identifier) @type) + +(interface_declaration + name: (identifier) @type) +(class_declaration + name: (identifier) @type) +(record_declaration + name: (identifier) @type) +(enum_declaration + name: (identifier) @type) +(constructor_declaration + name: (identifier) @constructor) +(constructor_initializer [ + "base" @constructor +]) + +(variable_declaration + (identifier) @type) +(object_creation_expression + (identifier) @type) + +; Generic Types. +(type_of_expression + (generic_name + (identifier) @type)) + +(type_argument_list + (generic_name + (identifier) @type)) + +(base_list + (generic_name + (identifier) @type)) + +(type_constraint + (generic_name + (identifier) @type)) + +(object_creation_expression + (generic_name + (identifier) @type)) + +(property_declaration + (generic_name + (identifier) @type)) + +(_ + type: (generic_name + (identifier) @type)) +; Generic Method invocation with generic type +(invocation_expression + function: (generic_name + . (identifier) @method.call)) + +(invocation_expression + (member_access_expression + (generic_name + (identifier) @method))) + +(base_list + (identifier) @type) + +(type_argument_list + (identifier) @type) + +(type_parameter_list + (type_parameter) @type) + +(type_parameter_constraints_clause + target: (identifier) @type) + +(attribute + name: (identifier) @attribute) + +(for_each_statement + type: (identifier) @type) + +(tuple_element + type: (identifier) @type) + +(tuple_expression + (argument + (declaration_expression + type: (identifier) @type))) + +(as_expression + right: (identifier) @type) + +(type_of_expression + (identifier) @type) + +(name_colon + (identifier) @parameter) + +(warning_directive) @text.warning +(error_directive) @exception + +(define_directive + (identifier) @constant) @constant.macro +(undef_directive + (identifier) @constant) @constant.macro + +(line_directive) @constant.macro +(line_directive + (preproc_integer_literal) @constant + (preproc_string_literal)? @string) + +(pragma_directive + (identifier) @constant) @constant.macro +(pragma_directive + (preproc_string_literal) @string) @constant.macro + +[ + (nullable_directive) + (region_directive) + (endregion_directive) +] @constant.macro + +[ + "if" + "else" + "switch" + "break" + "case" + (if_directive) + (elif_directive) + (else_directive) + (endif_directive) +] @conditional + +(if_directive + (identifier) @constant) +(elif_directive + (identifier) @constant) + +[ + "while" + "for" + "do" + "continue" + "goto" + "foreach" +] @repeat + +[ + "try" + "catch" + "throw" + "finally" +] @exception + +[ + "+" + "?" + ":" + "++" + "-" + "--" + "&" + "&&" + "|" + "||" + "!" + "!=" + "==" + "*" + "/" + "%" + "<" + "<=" + ">" + ">=" + "=" + "-=" + "+=" + "*=" + "/=" + "%=" + "^" + "^=" + "&=" + "|=" + "~" + ">>" + "<<" + "<<=" + ">>=" + "=>" +] @operator + +[ + ";" + "." + "," + ":" +] @punctuation.delimiter + +[ + "[" + "]" + "{" + "}" + "(" + ")" + "<" + ">" +] @punctuation.bracket + +[ + (this_expression) + (base_expression) +] @variable.builtin + +[ + "using" + "as" +] @include + +(alias_qualified_name + (identifier "global") @include) + +[ + "with" + "new" + "typeof" + "nameof" + "sizeof" + "is" + "and" + "or" + "not" + "stackalloc" + "in" + "out" + "ref" +] @keyword.operator + +[ + "lock" + "params" + "operator" + "default" + "implicit" + "explicit" + "override" + "async" + "await" + "class" + "delegate" + "enum" + "interface" + "namespace" + "struct" + "get" + "set" + "init" + "where" + "record" + "event" + "add" + "remove" + "checked" + "unchecked" + "fixed" +] @keyword + +[ + "const" + "extern" + "readonly" + "static" + "volatile" + "required" +] @storageclass + +[ + "abstract" + "private" + "protected" + "internal" + "public" + "partial" + "sealed" + "virtual" +] @type.qualifier + +(parameter_modifier) @operator + +(query_expression + (_ [ + "from" + "orderby" + "select" + "group" + "by" + "ascending" + "descending" + "equals" + "let" + ] @keyword)) + +[ + "return" + "yield" +] @keyword.return diff --git a/queries/c_sharp/injections.scm b/queries/c_sharp/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/c_sharp/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/queries/c_sharp/locals.scm b/queries/c_sharp/locals.scm new file mode 100644 index 000000000..c53eb1a19 --- /dev/null +++ b/queries/c_sharp/locals.scm @@ -0,0 +1,41 @@ +;; Definitions +(variable_declarator + . (identifier) @definition.var) + +(variable_declarator + (tuple_pattern + (identifier) @definition.var)) + +(declaration_expression + name: (identifier) @definition.var) + +(for_each_statement + left: (identifier) @definition.var) + +(for_each_statement + left: (tuple_pattern + (identifier) @definition.var)) + +(parameter + (identifier) @definition.parameter) + +(method_declaration + name: (identifier) @definition.method) + +(local_function_statement + name: (identifier) @definition.method) + +(property_declaration + name: (identifier) @definition) + +(type_parameter + (identifier) @definition.type) + +(class_declaration + name: (identifier) @definition) + +;; References +(identifier) @reference + +;; Scope +(block) @scope diff --git a/queries/clojure/folds.scm b/queries/clojure/folds.scm new file mode 100644 index 000000000..d54daade6 --- /dev/null +++ b/queries/clojure/folds.scm @@ -0,0 +1 @@ +(source (list_lit) @fold) diff --git a/queries/clojure/highlights.scm b/queries/clojure/highlights.scm new file mode 100644 index 000000000..3dc12d531 --- /dev/null +++ b/queries/clojure/highlights.scm @@ -0,0 +1,344 @@ +;; >> Explanation +;; Parsers for lisps are a bit weird in that they just return the raw forms. +;; This means we have to do a bit of extra work in the queries to get things +;; highlighted as they should be. +;; +;; For the most part this means that some things have to be assigned multiple +;; groups. +;; By doing this we can add a basic capture and then later refine it with more +;; specialied captures. +;; This can mean that sometimes things are highlighted weirdly because they +;; have multiple highlight groups applied to them. + + +;; >> Literals + +( + (dis_expr) @comment + (#set! "priority" 105) ; Higher priority to mark the whole sexpr as a comment +) +(kwd_lit) @symbol +(str_lit) @string +(num_lit) @number +(char_lit) @character +(bool_lit) @boolean +(nil_lit) @constant.builtin +(comment) @comment +(regex_lit) @string.regex + +["'" "`"] @string.escape + +["~" "~@" "#"] @punctuation.special + +["{" "}" "[" "]" "(" ")"] @punctuation.bracket + + + +;; >> Symbols + +; General symbol highlighting +(sym_lit) @variable + +; General function calls +(list_lit + . + (sym_lit) @function.call) +(anon_fn_lit + . + (sym_lit) @function.call) + +; Quoted symbols +(quoting_lit + (sym_lit) @symbol) +(syn_quoting_lit + (sym_lit) @symbol) + +; Used in destructure pattern +((sym_lit) @parameter + (#lua-match? @parameter "^[&]")) + +; Inline function variables +((sym_lit) @variable.builtin + (#match? @variable.builtin "^[%]")) + +; Constructor +((sym_lit) @constructor + (#match? @constructor "^-\\>[^\\>].*")) + +; Dynamic variables +((sym_lit) @variable.builtin + (#match? @variable.builtin "^[*].+[*]$")) + +; Gensym +;; Might not be needed +((sym_lit) @variable + (#match? @variable "^.*#$")) + +; Types +;; TODO: improve? +((sym_lit) @type + (#match? @type "^[A-Z][^/]*$")) +;; Symbols with `.` but not `/` +((sym_lit) @type + (#match? @type "^[^/]+[.][^/]*$")) + +; Interop +((sym_lit) @method + (#match? @method "^\\.[^-]")) +((sym_lit) @field + (#match? @field "^\\.-")) +((sym_lit) @field + (#match? @field "^[A-Z].*/.+")) +(list_lit + . + (sym_lit) @method + (#match? @method "^[A-Z].*/.+")) +;; TODO: Special casing for the `.` macro + +; Operators +((sym_lit) @operator + (#any-of? @operator + "*" "*'" "+" "+'" "-" "-'" "/" + "<" "<=" ">" ">=" "=" "==")) +((sym_lit) @keyword.operator + (#any-of? @keyword.operator + "not" "not=" "and" "or")) + +; Definition functions +((sym_lit) @keyword + (#any-of? @keyword + "def" "defonce" "defrecord" "defmacro" "definline" + "defmulti" "defmethod" "defstruct" "defprotocol" + "deftype")) +((sym_lit) @keyword + (#eq? @keyword "declare")) +((sym_lit) @keyword.function + (#match? @keyword.function "^(defn|defn-|fn|fn[*])$")) + +; Comment +((sym_lit) @comment + (#any-of? @comment "comment")) + +; Conditionals +((sym_lit) @conditional + (#any-of? @conditional + "case" "cond" "cond->" "cond->>" "condp")) +((sym_lit) @conditional + (#match? @conditional "^if(\\-.*)?$")) +((sym_lit) @conditional + (#match? @conditional "^when(\\-.*)?$")) + +; Repeats +((sym_lit) @repeat + (#any-of? @repeat + "doseq" "dotimes" "for" "loop" "recur" "while")) + +; Exception +((sym_lit) @exception + (#any-of? @exception + "throw" "try" "catch" "finally" "ex-info")) + +; Includes +((sym_lit) @include + (#any-of? @include "ns" "import" "require" "use")) + +; Builtin macros +;; TODO: Do all these items belong here? +((sym_lit) @function.macro + (#any-of? @function.macro + "." ".." "->" "->>" "amap" "areduce" "as->" "assert" + "binding" "bound-fn" "delay" "do" "dosync" + "doto" "extend-protocol" "extend-type" "future" + "gen-class" "gen-interface" "io!" "lazy-cat" + "lazy-seq" "let" "letfn" "locking" "memfn" "monitor-enter" + "monitor-exit" "proxy" "proxy-super" "pvalues" + "refer-clojure" "reify" "set!" "some->" "some->>" "sync" + "time" "unquote" "unquote-splicing" "var" "vswap!" + "ex-cause" "ex-data" "ex-message")) +((sym_lit) @function.macro + (#match? @function.macro "^with\\-.*$")) + +; All builtin functions +; (->> (ns-publics *ns*) +; (keep (fn [[s v]] (when-not (:macro (meta v)) s))) +; sort +; cp/print)) +;; ...and then lots of manual filtering... +((sym_lit) @function.builtin + (#any-of? @function.builtin + "->ArrayChunk" "->Eduction" "->Vec" "->VecNode" "->VecSeq" + "-cache-protocol-fn" "-reset-methods" "PrintWriter-on" + "StackTraceElement->vec" "Throwable->map" "accessor" + "aclone" "add-classpath" "add-tap" "add-watch" "agent" + "agent-error" "agent-errors" "aget" "alength" "alias" + "all-ns" "alter" "alter-meta!" "alter-var-root" "ancestors" + "any?" "apply" "array-map" "aset" "aset-boolean" "aset-byte" + "aset-char" "aset-double" "aset-float" "aset-int" + "aset-long" "aset-short" "assoc" "assoc!" "assoc-in" + "associative?" "atom" "await" "await-for" "await1" + "bases" "bean" "bigdec" "bigint" "biginteger" "bit-and" + "bit-and-not" "bit-clear" "bit-flip" "bit-not" "bit-or" + "bit-set" "bit-shift-left" "bit-shift-right" "bit-test" + "bit-xor" "boolean" "boolean-array" "boolean?" + "booleans" "bound-fn*" "bound?" "bounded-count" + "butlast" "byte" "byte-array" "bytes" "bytes?" + "cast" "cat" "char" "char-array" "char-escape-string" + "char-name-string" "char?" "chars" "chunk" "chunk-append" + "chunk-buffer" "chunk-cons" "chunk-first" "chunk-next" + "chunk-rest" "chunked-seq?" "class" "class?" + "clear-agent-errors" "clojure-version" "coll?" + "commute" "comp" "comparator" "compare" "compare-and-set!" + "compile" "complement" "completing" "concat" "conj" + "conj!" "cons" "constantly" "construct-proxy" "contains?" + "count" "counted?" "create-ns" "create-struct" "cycle" + "dec" "dec'" "decimal?" "dedupe" "default-data-readers" + "delay?" "deliver" "denominator" "deref" "derive" + "descendants" "destructure" "disj" "disj!" "dissoc" + "dissoc!" "distinct" "distinct?" "doall" "dorun" "double" + "double-array" "eduction" "empty" "empty?" "ensure" "ensure-reduced" + "enumeration-seq" "error-handler" "error-mode" "eval" + "even?" "every-pred" "every?" "extend" "extenders" "extends?" + "false?" "ffirst" "file-seq" "filter" "filterv" "find" + "find-keyword" "find-ns" "find-protocol-impl" + "find-protocol-method" "find-var" "first" "flatten" + "float" "float-array" "float?" "floats" "flush" "fn?" + "fnext" "fnil" "force" "format" "frequencies" + "future-call" "future-cancel" "future-cancelled?" + "future-done?" "future?" "gensym" "get" "get-in" + "get-method" "get-proxy-class" "get-thread-bindings" + "get-validator" "group-by" "halt-when" "hash" + "hash-combine" "hash-map" "hash-ordered-coll" "hash-set" + "hash-unordered-coll" "ident?" "identical?" "identity" + "ifn?" "in-ns" "inc" "inc'" "indexed?" "init-proxy" + "inst-ms" "inst-ms*" "inst?" "instance?" "int" "int-array" + "int?" "integer?" "interleave" "intern" "interpose" "into" + "into-array" "ints" "isa?" "iterate" "iterator-seq" "juxt" + "keep" "keep-indexed" "key" "keys" "keyword" "keyword?" + "last" "line-seq" "list" "list*" "list?" "load" "load-file" + "load-reader" "load-string" "loaded-libs" "long" "long-array" + "longs" "macroexpand" "macroexpand-1" "make-array" "make-hierarchy" + "map" "map-entry?" "map-indexed" "map?" "mapcat" "mapv" + "max" "max-key" "memoize" "merge" "merge-with" "meta" + "method-sig" "methods" "min" "min-key" "mix-collection-hash" + "mod" "munge" "name" "namespace" "namespace-munge" "nat-int?" + "neg-int?" "neg?" "newline" "next" "nfirst" "nil?" "nnext" + "not-any?" "not-empty" "not-every?" "ns-aliases" + "ns-imports" "ns-interns" "ns-map" "ns-name" "ns-publics" + "ns-refers" "ns-resolve" "ns-unalias" "ns-unmap" "nth" + "nthnext" "nthrest" "num" "number?" "numerator" "object-array" + "odd?" "parents" "partial" "partition" "partition-all" + "partition-by" "pcalls" "peek" "persistent!" "pmap" "pop" + "pop!" "pop-thread-bindings" "pos-int?" "pos?" "pr" + "pr-str" "prefer-method" "prefers" "primitives-classnames" + "print" "print-ctor" "print-dup" "print-method" "print-simple" + "print-str" "printf" "println" "println-str" "prn" "prn-str" + "promise" "proxy-call-with-super" "proxy-mappings" "proxy-name" + "push-thread-bindings" "qualified-ident?" "qualified-keyword?" + "qualified-symbol?" "quot" "rand" "rand-int" "rand-nth" "random-sample" + "range" "ratio?" "rational?" "rationalize" "re-find" "re-groups" + "re-matcher" "re-matches" "re-pattern" "re-seq" "read" + "read+string" "read-line" "read-string" "reader-conditional" + "reader-conditional?" "realized?" "record?" "reduce" + "reduce-kv" "reduced" "reduced?" "reductions" "ref" "ref-history-count" + "ref-max-history" "ref-min-history" "ref-set" "refer" + "release-pending-sends" "rem" "remove" "remove-all-methods" + "remove-method" "remove-ns" "remove-tap" "remove-watch" + "repeat" "repeatedly" "replace" "replicate" + "requiring-resolve" "reset!" "reset-meta!" "reset-vals!" + "resolve" "rest" "restart-agent" "resultset-seq" "reverse" + "reversible?" "rseq" "rsubseq" "run!" "satisfies?" + "second" "select-keys" "send" "send-off" "send-via" + "seq" "seq?" "seqable?" "seque" "sequence" "sequential?" + "set" "set-agent-send-executor!" "set-agent-send-off-executor!" + "set-error-handler!" "set-error-mode!" "set-validator!" + "set?" "short" "short-array" "shorts" "shuffle" + "shutdown-agents" "simple-ident?" "simple-keyword?" + "simple-symbol?" "slurp" "some" "some-fn" "some?" + "sort" "sort-by" "sorted-map" "sorted-map-by" + "sorted-set" "sorted-set-by" "sorted?" "special-symbol?" + "spit" "split-at" "split-with" "str" "string?" + "struct" "struct-map" "subs" "subseq" "subvec" "supers" + "swap!" "swap-vals!" "symbol" "symbol?" "tagged-literal" + "tagged-literal?" "take" "take-last" "take-nth" "take-while" + "tap>" "test" "the-ns" "thread-bound?" "to-array" + "to-array-2d" "trampoline" "transduce" "transient" + "tree-seq" "true?" "type" "unchecked-add" "unchecked-add-int" + "unchecked-byte" "unchecked-char" "unchecked-dec" + "unchecked-dec-int" "unchecked-divide-int" "unchecked-double" + "unchecked-float" "unchecked-inc" "unchecked-inc-int" + "unchecked-int" "unchecked-long" "unchecked-multiply" + "unchecked-multiply-int" "unchecked-negate" "unchecked-negate-int" + "unchecked-remainder-int" "unchecked-short" "unchecked-subtract" + "unchecked-subtract-int" "underive" "unquote" + "unquote-splicing" "unreduced" "unsigned-bit-shift-right" + "update" "update-in" "update-proxy" "uri?" "uuid?" + "val" "vals" "var-get" "var-set" "var?" "vary-meta" "vec" + "vector" "vector-of" "vector?" "volatile!" "volatile?" + "vreset!" "with-bindings*" "with-meta" "with-redefs-fn" "xml-seq" + "zero?" "zipmap")) + + + +;; >> Context based highlighting + +;; def-likes +;; Correctly highlight docstrings +;(list_lit + ;. + ;(sym_lit) @_keyword ; Don't really want to highlight twice + ;(#any-of? @_keyword + ;"def" "defonce" "defrecord" "defmacro" "definline" + ;"defmulti" "defmethod" "defstruct" "defprotocol" + ;"deftype") + ;. + ;(sym_lit) + ;. + ;;; TODO: Add @comment highlight + ;(str_lit)? + ;. + ;(_)) + +; Function definitions +(list_lit + . + (sym_lit) @_keyword.function + (#any-of? @_keyword.function "fn" "fn*" "defn" "defn-") + . + (sym_lit)? @function + . + ;; TODO: Add @comment highlight + (str_lit)?) +;; TODO: Fix parameter highlighting +;; I think there's a bug here in nvim-treesitter +;; TODO: Reproduce bug and file ticket + ;. + ;[(vec_lit + ; (sym_lit)* @parameter) + ; (list_lit + ; (vec_lit + ; (sym_lit)* @parameter))]) + +;[((list_lit +; (vec_lit +; (sym_lit) @parameter) +; (_) +; + +; ((vec_lit +; (sym_lit) @parameter) +; (_))) + + +; Meta punctuation +;; NOTE: When the above `Function definitions` query captures the +;; the @function it also captures the child meta_lit +;; We capture the meta_lit symbol (^) after so that the later +;; highlighting overrides the former +"^" @punctuation.special + +;; namespaces +(list_lit + . + (sym_lit) @_include + (#eq? @_include "ns") + . + (sym_lit) @namespace) diff --git a/queries/clojure/injections.scm b/queries/clojure/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/clojure/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/runtime/queries/clojure/locals.scm b/queries/clojure/locals.scm similarity index 100% rename from runtime/queries/clojure/locals.scm rename to queries/clojure/locals.scm diff --git a/queries/cmake/folds.scm b/queries/cmake/folds.scm new file mode 100644 index 000000000..9ac59ad4c --- /dev/null +++ b/queries/cmake/folds.scm @@ -0,0 +1,8 @@ +[ + (if_condition) + (foreach_loop) + (while_loop) + (function_def) + (macro_def) + (block_def) +] @fold diff --git a/queries/cmake/highlights.scm b/queries/cmake/highlights.scm new file mode 100644 index 000000000..0e846507d --- /dev/null +++ b/queries/cmake/highlights.scm @@ -0,0 +1,242 @@ +[ + (quoted_argument) + (bracket_argument) +] @string + +(variable_ref) @none +(variable) @variable + +[ + (bracket_comment) + (line_comment) +] @comment @spell + +(normal_command (identifier) @function) + +["ENV" "CACHE"] @storageclass +["$" "{" "}" "<" ">"] @punctuation.special +["(" ")"] @punctuation.bracket + +[ + (function) + (endfunction) + (macro) + (endmacro) +] @keyword.function + +[ + (if) + (elseif) + (else) + (endif) +] @conditional + +[ + (foreach) + (endforeach) + (while) + (endwhile) +] @repeat + +(normal_command + (identifier) @repeat + (#match? @repeat "\\c^(continue|break)$") +) +(normal_command + (identifier) @keyword.return + (#match? @keyword.return "\\c^return$") +) + +(function_command + (function) + . (argument) @function + (argument)* @parameter +) + +(macro_command + (macro) + . (argument) @function.macro + (argument)* @parameter +) + +(block_def + (block_command + (block) @function.builtin + (argument (unquoted_argument) @constant) + (#any-of? @constant "SCOPE_FOR" "POLICIES" "VARIABLES" "PROPAGATE") + ) + (endblock_command (endblock) @function.builtin) +) + +((argument) @boolean + (#match? @boolean "\\c^(1|on|yes|true|y|0|off|no|false|n|ignore|notfound|.*-notfound)$") +) + +(if_command + (if) + (argument) @keyword.operator + (#any-of? @keyword.operator "NOT" "AND" "OR" + "COMMAND" "POLICY" "TARGET" "TEST" "DEFINED" "IN_LIST" + "EXISTS" "IS_NEWER_THAN" "IS_DIRECTORY" "IS_SYMLINK" "IS_ABSOLUTE" + "MATCHES" + "LESS" "GREATER" "EQUAL" "LESS_EQUAL" "GREATER_EQUAL" + "STRLESS" "STRGREATER" "STREQUAL" "STRLESS_EQUAL" "STRGREATER_EQUAL" + "VERSION_LESS" "VERSION_GREATER" "VERSION_EQUAL" "VERSION_LESS_EQUAL" "VERSION_GREATER_EQUAL" + ) +) + +(normal_command + (identifier) @function.builtin + (#match? @function.builtin "\\c^(cmake_host_system_information|cmake_language|cmake_minimum_required|cmake_parse_arguments|cmake_path|cmake_policy|configure_file|execute_process|file|find_file|find_library|find_package|find_path|find_program|foreach|get_cmake_property|get_directory_property|get_filename_component|get_property|include|include_guard|list|macro|mark_as_advanced|math|message|option|separate_arguments|set|set_directory_properties|set_property|site_name|string|unset|variable_watch|add_compile_definitions|add_compile_options|add_custom_command|add_custom_target|add_definitions|add_dependencies|add_executable|add_library|add_link_options|add_subdirectory|add_test|aux_source_directory|build_command|create_test_sourcelist|define_property|enable_language|enable_testing|export|fltk_wrap_ui|get_source_file_property|get_target_property|get_test_property|include_directories|include_external_msproject|include_regular_expression|install|link_directories|link_libraries|load_cache|project|remove_definitions|set_source_files_properties|set_target_properties|set_tests_properties|source_group|target_compile_definitions|target_compile_features|target_compile_options|target_include_directories|target_link_directories|target_link_libraries|target_link_options|target_precompile_headers|target_sources|try_compile|try_run|ctest_build|ctest_configure|ctest_coverage|ctest_empty_binary_directory|ctest_memcheck|ctest_read_custom_files|ctest_run_script|ctest_sleep|ctest_start|ctest_submit|ctest_test|ctest_update|ctest_upload)$") +) + +(normal_command + (identifier) @_function + . (argument) @variable + (#match? @_function "\\c^set$") +) + +(normal_command + (identifier) @_function + (#match? @_function "\\c^set$") + ( + (argument) @constant + (#any-of? @constant "PARENT_SCOPE") + ) . +) + +(normal_command + (identifier) @_function + (#match? @_function "\\c^set$") + . (argument) + ( + (argument) @_cache @storageclass + . + (argument) @_type @type + (#any-of? @_cache "CACHE") + (#any-of? @_type "BOOL" "FILEPATH" "PATH" "STRING" "INTERNAL") + ) +) +(normal_command + (identifier) @_function + (#match? @_function "\\c^set$") + . (argument) + (argument) @_cache + (#any-of? @_cache "CACHE") + ( + (argument) @_force @constant + (#any-of? @_force "FORCE") + ) . +) + +(normal_command + (identifier) @_function + (#match? @_function "\\c^unset$") + . (argument) @variable +) +(normal_command + (identifier) @_function + (#match? @_function "\\c^unset$") + . (argument) + (argument) @storageclass + (#any-of? @storageclass "CACHE" "PARENT_SCOPE") +) + +(normal_command + (identifier) @_function + (#match? @_function "\\c^list$") + . (argument) @constant + (#any-of? @constant "LENGTH" "GET" "JOIN" "SUBLIST" "FIND") + . (argument) @variable + (argument) @variable . +) +(normal_command + (identifier) @_function + (#match? @_function "\\c^list$") + . (argument) @constant + . (argument) @variable + (#any-of? @constant "APPEND" "FILTER" "INSERT" + "POP_BACK" "POP_FRONT" "PREPEND" + "REMOVE_ITEM" "REMOVE_AT" "REMOVE_DUPLICATES" + "REVERSE" "SORT") +) +(normal_command + (identifier) @_function + (#match? @_function "\\c^list$") + . (argument) @_transform @constant + . (argument) @variable + . (argument) @_action @constant + (#match? @_transform "TRANSFORM") + (#any-of? @_action "APPEND" "PREPEND" "TOUPPER" "TOLOWER" "STRIP" "GENEX_STRIP" "REPLACE") +) +(normal_command + (identifier) @_function + (#match? @_function "\\c^list$") + . (argument) @_transform @constant + . (argument) @variable + . (argument) @_action @constant + . (argument)? @_selector @constant + (#match? @_transform "TRANSFORM") + (#any-of? @_action "APPEND" "PREPEND" "TOUPPER" "TOLOWER" "STRIP" "GENEX_STRIP" "REPLACE") + (#any-of? @_selector "AT" "FOR" "REGEX") +) +(normal_command + (identifier) @_function + (#match? @_function "\\c^list$") + . (argument) @_transform @constant + (argument) @constant . + (argument) @variable + (#match? @_transform "TRANSFORM") + (#match? @constant "OUTPUT_VARIABLE") +) + +(normal_command + (identifier) @_function + (#match? @_function "\\c^add_custom_target$") + . (argument) + (argument) @constant + (#any-of? @constant "ALL" "COMMAND" "DEPENDS" "BYPRODUCTS" "WORKING_DIRECTORY" "COMMENT" + "JOB_POOL" "VERBATIM" "USES_TERMINAL" "COMMAND_EXPAND_LISTS" "SOURCES") +) + +(normal_command + (identifier) @_function + (#match? @_function "\\c^add_custom_command$") + (argument) @constant + (#any-of? @constant "OUTPUT" "COMMAND" "MAIN_DEPENDENCY" "DEPENDS" "BYPRODUCTS" "IMPLICIT_DEPENDS" "WORKING_DIRECTORY" + "COMMENT" "DEPFILE" "JOB_POOL" "VERBATIM" "APPEND" "USES_TERMINAL" "COMMAND_EXPAND_LISTS") +) + +(normal_command + (identifier) @_function + (#match? @_function "\\c^include$") + (argument) @constant + (#any-of? @constant "OPTIONAL" "NO_POLICY_SCOPE") +) +(normal_command + (identifier) @_function + (#match? @_function "\\c^include$") + (argument) @constant + . + (argument) @variable + (#match? @constant "RESULT_VARIABLE") +) + +(normal_command + (identifier) @_function + (#match? @_function "\\c^project$") + (argument) @constant + (#any-of? @constant "VERSION" "DESCRIPTION" "HOMEPAGE_URL" "LANGUAGES") +) + +(normal_command + (identifier) @_function + (#match? @_function "\\c^cmake_minimum_required$") + (argument) @constant + (#any-of? @constant "VERSION" "FATAL_ERROR") +) + +(escape_sequence) @string.escape + +((source_file . (line_comment) @preproc) + (#match? @preproc "^#!/")) diff --git a/queries/comment/highlights.scm b/queries/comment/highlights.scm new file mode 100644 index 000000000..66bc99cc7 --- /dev/null +++ b/queries/comment/highlights.scm @@ -0,0 +1,44 @@ +(_) @spell + +[ + "(" + ")" +] @punctuation.bracket + +":" @punctuation.delimiter + +(tag + (name) @text.todo + (user)? @constant) + +((tag ((name) @text.todo)) + (#eq? @text.todo "TODO")) + +("text" @text.todo + (#eq? @text.todo "TODO")) + +((tag ((name) @text.note)) + (#any-of? @text.note "NOTE" "XXX")) + +("text" @text.note + (#any-of? @text.note "NOTE" "XXX")) + +((tag ((name) @text.warning)) + (#any-of? @text.warning "HACK" "WARNING")) + +("text" @text.warning + (#any-of? @text.warning "HACK" "WARNING")) + +((tag ((name) @text.danger)) + (#any-of? @text.danger "FIXME" "BUG")) + +("text" @text.danger + (#any-of? @text.danger "FIXME" "BUG")) + +; Issue number (#123) +("text" @number + (#lua-match? @number "^#[0-9]+$")) + +; User mention (@user) +("text" @constant + (#lua-match? @constant "^[@][a-zA-Z0-9_-]+$")) diff --git a/queries/commonlisp/folds.scm b/queries/commonlisp/folds.scm new file mode 100644 index 000000000..d54daade6 --- /dev/null +++ b/queries/commonlisp/folds.scm @@ -0,0 +1 @@ +(source (list_lit) @fold) diff --git a/queries/commonlisp/highlights.scm b/queries/commonlisp/highlights.scm new file mode 100644 index 000000000..5cf7c1eb0 --- /dev/null +++ b/queries/commonlisp/highlights.scm @@ -0,0 +1,187 @@ +(sym_lit) @variable + +;; A highlighting for functions/macros in th cl namespace is available in theHamsta/nvim-treesitter-commonlisp +;(list_lit . (sym_lit) @function.builtin (#cl-standard-function? @function.builtin)) +;(list_lit . (sym_lit) @function.builtin (#cl-standard-macro? @function.macro)) + +(dis_expr) @comment + +(defun_keyword) @function.macro +(defun_header + function_name: (_) @function) +(defun_header + lambda_list: (list_lit (sym_lit) @parameter)) +(defun_header + keyword: (defun_keyword "defmethod") + lambda_list: (list_lit (list_lit . (sym_lit) . (sym_lit) @symbol))) +(defun_header + lambda_list: (list_lit (list_lit . (sym_lit) @parameter . (_)))) +(defun_header + specifier: (sym_lit) @symbol) + +[":" "::" "."] @punctuation.special + +[ + (accumulation_verb) + (for_clause_word) + "for" + "and" + "finally" + "thereis" + "always" + "when" + "if" + "unless" + "else" + "do" + "loop" + "below" + "in" + "from" + "across" + "repeat" + "being" + "into" + "with" + "as" + "while" + "until" + "return" + "initially" +] @function.macro +"=" @operator + +(include_reader_macro) @symbol +["#C" "#c"] @number + +[(kwd_lit) (self_referential_reader_macro)] @symbol + +(package_lit + package: (_) @namespace) +"cl" @namespace + +(str_lit) @string + +(num_lit) @number + +((sym_lit) @boolean (#match? @boolean "^(t|T)$")) + +(nil_lit) @constant.builtin + +(comment) @comment + +;; dynamic variables +((sym_lit) @variable.builtin + (#match? @variable.builtin "^[*].+[*]$")) + +;; quote +"'" @string.escape +(format_specifier) @string.escape +(quoting_lit) @string.escape + +;; syntax quote +"`" @string.escape +"," @string.escape +",@" @string.escape +(syn_quoting_lit) @string.escape +(unquoting_lit) @none +(unquote_splicing_lit) @none + + +["(" ")"] @punctuation.bracket + +(block_comment) @comment + + +(with_clause + type: (_) @type) +(for_clause + type: (_) @type) + +;; defun-like things +(list_lit + . + (sym_lit) @function.macro + . + (sym_lit) @function + (#eq? @function.macro "deftest")) + +;;; Macros and Special Operators +(list_lit + . + (sym_lit) @function.macro + ;; For a complete and more efficient version install theHamsta/nvim-treesitter-commonlisp + (#any-of? @function.macro + "let" + "function" + "the" + "unwind-protect" + "labels" + "flet" + "tagbody" + "go" + "symbol-macrolet" + "symbol-macrolet" + "progn" + "prog1" + "error" + "or" + "and" + "defvar" + "defparameter" + "in-package" + "defpackage" + "case" + "ecase" + "typecase" + "etypecase" + "defstruct" + "defclass" + "if" + "when" + "unless" + "cond" + "switch" + "declaim" + "optimize")) + +;; constant +((sym_lit) @constant + (#match? @constant "^[+].+[+]$")) + +(var_quoting_lit + marker: "#'" @symbol + value: (_) @symbol) + +["#" "#p" "#P"] @symbol + +(list_lit + . + (sym_lit) @function.builtin + ;; For a complete and more efficient version install theHamsta/nvim-treesitter-commonlisp + (#any-of? @function.builtin + "mapcar" + "reduce" + "remove-if-not" + "cons" + "car" + "last" + "nth" + "equal" + "cdr" + "first" + "rest" + "format")) + +(list_lit + . + (sym_lit) @operator + (#match? @operator "^([+*-+=<>]|<=|>=|/=)$")) + + +((sym_lit) @symbol +(#match? @symbol "^[&]")) + +[(array_dimension) "#0A" "#0a"] @number + +(char_lit) @character diff --git a/queries/commonlisp/locals.scm b/queries/commonlisp/locals.scm new file mode 100644 index 000000000..acdf965b7 --- /dev/null +++ b/queries/commonlisp/locals.scm @@ -0,0 +1,72 @@ + +(defun_header + function_name: (sym_lit) @definition.function (#set! definition.function.scope "parent")) +(defun_header + lambda_list: (list_lit (sym_lit) @definition.parameter)) + +(defun_header + keyword: (defun_keyword "defmethod") + lambda_list: (list_lit (list_lit . (sym_lit) . (sym_lit) @definition.type))) +(defun_header + lambda_list: (list_lit (list_lit . (sym_lit) @definition.parameter . (_)))) + +(sym_lit) @reference + +(defun) @scope + +((list_lit . (sym_lit) @_defvar . (sym_lit) @definition.var) +(#match? @_defvar "^(cl:)?(defvar|defparameter)$")) + +(list_lit + . + (sym_lit) @_deftest + . + (sym_lit) @definition.function + (#match? @_deftest "^(deftest)$")) @scope + +(list_lit + . + (sym_lit) @_deftest + . + (sym_lit) @definition.function + (#match? @_deftest "^(deftest)$")) @scope + +(for_clause . (sym_lit) @definition.var) +(with_clause . (sym_lit) @definition.var) +(loop_macro) @scope + +(list_lit + . + (sym_lit) @_let (#match? @_let "(cl:|cffi:)?(with-accessors|with-foreign-objects|let[*]?)") + . + (list_lit (list_lit . (sym_lit) @definition.var))) @scope + +(list_lit + . + (sym_lit) @_let (#match? @_let "(cl:|alexandria:)?(with-gensyms|dotimes|with-foreign-object)") + . + (list_lit . (sym_lit) @definition.var)) @scope + +(list_lit + . + (kwd_lit) @_import_from (#eq? @_import_from ":import-from") + . + (_) + (kwd_lit (kwd_symbol) @definition.import)) + +(list_lit + . + (kwd_lit) @_import_from (#eq? @_import_from ":import-from") + . + (_) + (sym_lit) @definition.import) + +(list_lit + . + (kwd_lit) @_use (#eq? @_use ":use") + (kwd_lit (kwd_symbol) @definition.import)) + +(list_lit + . + (kwd_lit) @_use (#eq? @_use ":use") + (sym_lit) @definition.import) diff --git a/queries/cooklang/highlights.scm b/queries/cooklang/highlights.scm new file mode 100644 index 000000000..4ced465bd --- /dev/null +++ b/queries/cooklang/highlights.scm @@ -0,0 +1,22 @@ +(metadata) @comment + +(ingredient + "@" @tag + (name)? @text.title + (amount + (quantity)? @number + (units)? @tag.attribute)?) + +(timer + "~" @tag + (name)? @text.title + (amount + (quantity)? @number + (units)? @tag.attribute)?) + +(cookware + "#" @tag + (name)? @text.title + (amount + (quantity)? @number + (units)? @tag.attribute)?) diff --git a/queries/cpp/folds.scm b/queries/cpp/folds.scm new file mode 100644 index 000000000..23d623b04 --- /dev/null +++ b/queries/cpp/folds.scm @@ -0,0 +1,14 @@ +; inherits: c + +[ + (for_range_loop) + (class_specifier) + (field_declaration + type: (enum_specifier) + default_value: (initializer_list)) + (template_declaration) + (namespace_definition) + (try_statement) + (catch_clause) + (lambda_expression) +] @fold diff --git a/queries/cpp/highlights.scm b/queries/cpp/highlights.scm new file mode 100644 index 000000000..1f770e9f8 --- /dev/null +++ b/queries/cpp/highlights.scm @@ -0,0 +1,188 @@ +; inherits: c + +((identifier) @field + (#match? @field "(^_|^m_|_$)")) + +(parameter_declaration + declarator: (reference_declarator) @parameter) + +; function(Foo ...foo) +(variadic_parameter_declaration + declarator: (variadic_declarator + (_) @parameter)) +; int foo = 0 +(optional_parameter_declaration + declarator: (_) @parameter) + +;(field_expression) @parameter ;; How to highlight this? +(template_function + name: (identifier) @function) + +(template_method + name: (field_identifier) @method) + +(((field_expression + (field_identifier) @method)) @_parent + (#has-parent? @_parent template_method function_declarator call_expression)) + +(field_declaration + (field_identifier) @field) + +(field_initializer + (field_identifier) @property) + +(function_declarator + declarator: (field_identifier) @method) + +(concept_definition + name: (identifier) @type.definition) + +(alias_declaration + name: (type_identifier) @type.definition) + +(auto) @type.builtin + +(namespace_identifier) @namespace +((namespace_identifier) @type + (#lua-match? @type "^[A-Z]")) +((namespace_identifier) @constant + (#lua-match? @constant "^[A-Z][A-Z_0-9]*$")) +(case_statement + value: (qualified_identifier (identifier) @constant)) +(namespace_definition + name: (identifier) @namespace) + +(using_declaration . "using" . "namespace" . [(qualified_identifier) (identifier)] @namespace) + +(destructor_name + (identifier) @method) + +(function_declarator + declarator: (qualified_identifier + name: (identifier) @function)) +(function_declarator + declarator: (qualified_identifier + name: (qualified_identifier + name: (identifier) @function))) +((function_declarator + declarator: (qualified_identifier + name: (identifier) @constructor)) + (#lua-match? @constructor "^[A-Z]")) + +(operator_name) @function +"operator" @function +"static_assert" @function.builtin + +(call_expression + function: (qualified_identifier + name: (identifier) @function.call)) +(call_expression + function: (qualified_identifier + name: (qualified_identifier + name: (identifier) @function.call))) +(call_expression + function: + (qualified_identifier + name: (qualified_identifier + name: (qualified_identifier + name: (identifier) @function.call)))) + +(call_expression + function: (field_expression + field: (field_identifier) @function.call)) + +((call_expression + function: (identifier) @constructor) +(#lua-match? @constructor "^[A-Z]")) +((call_expression + function: (qualified_identifier + name: (identifier) @constructor)) +(#lua-match? @constructor "^[A-Z]")) + +((call_expression + function: (field_expression + field: (field_identifier) @constructor)) +(#lua-match? @constructor "^[A-Z]")) + +;; constructing a type in an initializer list: Constructor (): **SuperType (1)** +((field_initializer + (field_identifier) @constructor + (argument_list)) + (#lua-match? @constructor "^[A-Z]")) + + +; Constants + +(this) @variable.builtin +(nullptr) @constant + +(true) @boolean +(false) @boolean + +; Literals + +(raw_string_literal) @string + +; Keywords + +[ + "try" + "catch" + "noexcept" + "throw" +] @exception + + +[ + "class" + "decltype" + "explicit" + "friend" + "namespace" + "override" + "template" + "typename" + "using" + "co_await" + "concept" + "requires" +] @keyword + +[ + "public" + "private" + "protected" + "virtual" + "final" +] @type.qualifier + +[ + "co_yield" + "co_return" +] @keyword.return + +[ + "new" + "delete" + + "xor" + "bitand" + "bitor" + "compl" + "not" + "xor_eq" + "and_eq" + "or_eq" + "not_eq" + "and" + "or" +] @keyword.operator + +"<=>" @operator + +"::" @punctuation.delimiter + +(template_argument_list + ["<" ">"] @punctuation.bracket) + +(literal_suffix) @operator diff --git a/queries/cpp/indents.scm b/queries/cpp/indents.scm new file mode 100644 index 000000000..f1007dd28 --- /dev/null +++ b/queries/cpp/indents.scm @@ -0,0 +1,10 @@ +; inherits: c + +[ + (class_specifier) + (condition_clause) +] @indent + +((field_initializer_list) @indent + (#set! "start_at_same_line" 1)) +(access_specifier) @branch diff --git a/queries/cpp/injections.scm b/queries/cpp/injections.scm new file mode 100644 index 000000000..13842120d --- /dev/null +++ b/queries/cpp/injections.scm @@ -0,0 +1,3 @@ +(preproc_arg) @cpp + +(comment) @comment diff --git a/queries/cpp/locals.scm b/queries/cpp/locals.scm new file mode 100644 index 000000000..c48a7cc39 --- /dev/null +++ b/queries/cpp/locals.scm @@ -0,0 +1,71 @@ +; inherits: c + +;; Parameters +(variadic_parameter_declaration + declarator: (variadic_declarator + (identifier) @definition.parameter)) +(optional_parameter_declaration + declarator: (identifier) @definition.parameter) +;; Class / struct definitions +(class_specifier) @scope + +(reference_declarator + (identifier) @definition.var) + +(variadic_declarator + (identifier) @definition.var) + +(struct_specifier + name: (qualified_identifier + name: (type_identifier) @definition.type)) + +(class_specifier + name: (type_identifier) @definition.type) + +(concept_definition + name: (identifier) @definition.type) + +(class_specifier + name: (qualified_identifier + name: (type_identifier) @definition.type)) + +(alias_declaration + name: (type_identifier) @definition.type) + +;template +(type_parameter_declaration + (type_identifier) @definition.type) +(template_declaration) @scope + +;; Namespaces +(namespace_definition + name: (identifier) @definition.namespace + body: (_) @scope) + +((namespace_identifier) @reference + (set! reference.kind "namespace")) + +;; Function definitions +(template_function + name: (identifier) @definition.function) @scope + +(template_method + name: (field_identifier) @definition.method) @scope + +(function_declarator + declarator: (qualified_identifier + name: (identifier) @definition.function)) @scope + +(field_declaration + declarator: (function_declarator + (field_identifier) @definition.method)) + +(lambda_expression) @scope + +;; Control structures +(try_statement + body: (_) @scope) + +(catch_clause) @scope + +(requires_expression) @scope diff --git a/queries/css/folds.scm b/queries/css/folds.scm new file mode 100644 index 000000000..9d2995c48 --- /dev/null +++ b/queries/css/folds.scm @@ -0,0 +1,3 @@ +[ + (rule_set) +] @fold diff --git a/queries/css/highlights.scm b/queries/css/highlights.scm new file mode 100644 index 000000000..bacc5bd26 --- /dev/null +++ b/queries/css/highlights.scm @@ -0,0 +1,91 @@ +[ + "@media" + "@charset" + "@namespace" + "@supports" + "@keyframes" + (at_keyword) + (to) + (from) + ] @keyword + +"@import" @include + +(comment) @comment @spell + +[ + (tag_name) + (nesting_selector) + (universal_selector) + ] @type + +(function_name) @function + +[ + "~" + ">" + "+" + "-" + "*" + "/" + "=" + "^=" + "|=" + "~=" + "$=" + "*=" + "and" + "or" + "not" + "only" + ] @operator + +(important) @type.qualifier + +(attribute_selector (plain_value) @string) +(pseudo_element_selector "::" (tag_name) @property) +(pseudo_class_selector (class_name) @property) + +[ + (class_name) + (id_name) + (property_name) + (feature_name) + (attribute_name) + ] @property + +(namespace_name) @namespace + +((property_name) @type.definition + (#match? @type.definition "^--")) +((plain_value) @type + (#match? @type "^--")) + +[ + (string_value) + (color_value) + (unit) + ] @string + +[ + (integer_value) + (float_value) + ] @number + +[ + "#" + "," + "." + ":" + "::" + ";" + ] @punctuation.delimiter + +[ + "{" + ")" + "(" + "}" + ] @punctuation.bracket + +(ERROR) @error diff --git a/queries/css/indents.scm b/queries/css/indents.scm new file mode 100644 index 000000000..1ea8a336f --- /dev/null +++ b/queries/css/indents.scm @@ -0,0 +1,9 @@ +[ + (block) + (declaration) +] @indent + +(block ("}") @branch) +("}") @dedent + +(comment) @ignore diff --git a/queries/css/injections.scm b/queries/css/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/css/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/runtime/queries/cuda/folds.scm b/queries/cuda/folds.scm similarity index 100% rename from runtime/queries/cuda/folds.scm rename to queries/cuda/folds.scm diff --git a/queries/cuda/highlights.scm b/queries/cuda/highlights.scm new file mode 100644 index 000000000..20a753be3 --- /dev/null +++ b/queries/cuda/highlights.scm @@ -0,0 +1,11 @@ +; inherits: cpp + +[ "<<<" ">>>" ] @punctuation.bracket + +[ + "__host__" + "__device__" + "__forceinline__" +] @storageclass + +"__launch_bounds__" @type.qualifier diff --git a/runtime/queries/cuda/indents.scm b/queries/cuda/indents.scm similarity index 100% rename from runtime/queries/cuda/indents.scm rename to queries/cuda/indents.scm diff --git a/queries/cuda/injections.scm b/queries/cuda/injections.scm new file mode 100644 index 000000000..49fe7c532 --- /dev/null +++ b/queries/cuda/injections.scm @@ -0,0 +1,3 @@ +(preproc_arg) @cuda + +(comment) @comment diff --git a/runtime/queries/cuda/locals.scm b/queries/cuda/locals.scm similarity index 100% rename from runtime/queries/cuda/locals.scm rename to queries/cuda/locals.scm diff --git a/queries/d/folds.scm b/queries/d/folds.scm new file mode 100644 index 000000000..be4dee45e --- /dev/null +++ b/queries/d/folds.scm @@ -0,0 +1 @@ +(block_statement) @fold diff --git a/queries/d/highlights.scm b/queries/d/highlights.scm new file mode 100644 index 000000000..8bec1ca10 --- /dev/null +++ b/queries/d/highlights.scm @@ -0,0 +1,277 @@ +;; Misc + +[ + (line_comment) + (block_comment) + (nesting_block_comment) +] @comment + +[ + "(" ")" + "[" "]" + "{" "}" +] @punctuation.bracket + +[ + "," + ";" + "." + ":" +] @punctuation.delimiter + +[ + ".." + "$" +] @punctuation.special + +;; Constants + +[ + "__FILE_FULL_PATH__" + "__FILE__" + "__FUNCTION__" + "__LINE__" + "__MODULE__" + "__PRETTY_FUNCTION__" +] @constant.macro + +[ + (wysiwyg_string) + (alternate_wysiwyg_string) + (double_quoted_string) + (hex_string) + (delimited_string) + (token_string) +] @string + +(character_literal) @character + +(integer_literal) @number + +(float_literal) @float + +[ + "true" + "false" +] @boolean + +;; Functions + +(func_declarator + (identifier) @function +) + +[ + "__traits" + "__vector" + "assert" + "is" + "mixin" + "pragma" + "typeid" +] @function.builtin + +(import_expression + "import" @function.builtin +) + +(parameter + (var_declarator + (identifier) @parameter + ) +) + +(function_literal + (identifier) @parameter +) + +(constructor + "this" @constructor +) + +(destructor + "this" @constructor +) + +;; Keywords + +[ + "case" + "default" + "else" + "if" + "switch" +] @conditional + +[ + "break" + "continue" + "do" + "for" + "foreach" + "foreach_reverse" + "while" +] @repeat + +[ + "__parameters" + "alias" + "align" + "asm" + "auto" + "body" + "class" + "debug" + "enum" + "export" + "goto" + "interface" + "invariant" + "macro" + "out" + "override" + "package" + "static" + "struct" + "template" + "union" + "unittest" + "version" + "with" +] @keyword + +[ + "delegate" + "function" +] @keyword.function + +"return" @keyword.return + +[ + "cast" + "new" +] @keyword.operator + +[ + "+" + "++" + "+=" + "-" + "--" + "-=" + "*" + "*=" + "%" + "%=" + "^" + "^=" + "^^" + "^^=" + "/" + "/=" + "|" + "|=" + "||" + "~" + "~=" + "=" + "==" + "=>" + "<" + "<=" + "<<" + "<<=" + ">" + ">=" + ">>" + ">>=" + ">>>" + ">>>=" + "!" + "!=" + "&" + "&&" +] @operator + +[ + "catch" + "finally" + "throw" + "try" +] @exception + +"null" @constant.builtin + +[ + "__gshared" + "const" + "immutable" + "shared" +] @storageclass + +[ + "abstract" + "deprecated" + "extern" + "final" + "inout" + "lazy" + "nothrow" + "private" + "protected" + "public" + "pure" + "ref" + "scope" + "synchronized" +] @type.qualifier + +(alias_assignment + . (identifier) @type.definition) + +(module_declaration + "module" @include +) + +(import_declaration + "import" @include +) + +(type) @type + +(catch_parameter + (qualified_identifier) @type +) + +(var_declarations + (qualified_identifier) @type +) + +(func_declaration + (qualified_identifier) @type +) + +(parameter + (qualified_identifier) @type +) + +(class_declaration + (identifier) @type +) + +(fundamental_type) @type.builtin + +(module_fully_qualified_name (packages (package_name) @namespace)) +(module_name) @namespace + +(at_attribute) @attribute + +(user_defined_attribute + "@" @attribute +) + +;; Variables + +(primary_expression + "this" @variable.builtin +) diff --git a/queries/d/indents.scm b/queries/d/indents.scm new file mode 100644 index 000000000..7a6df759c --- /dev/null +++ b/queries/d/indents.scm @@ -0,0 +1,17 @@ +[ + (block_statement) + (case_statement) + (token_string) +] @indent + +[ + "(" ")" + "{" "}" + "[" "]" +] @branch + +[ + (line_comment) + (block_comment) + (nesting_block_comment) +] @ignore diff --git a/queries/d/injections.scm b/queries/d/injections.scm new file mode 100644 index 000000000..d95514370 --- /dev/null +++ b/queries/d/injections.scm @@ -0,0 +1,7 @@ +[ + (line_comment) + (block_comment) + (nesting_block_comment) +] @comment + +(token_string_tokens) @d diff --git a/queries/dart/highlights.scm b/queries/dart/highlights.scm new file mode 100644 index 000000000..19991c66f --- /dev/null +++ b/queries/dart/highlights.scm @@ -0,0 +1,269 @@ +(dotted_identifier_list) @string + +; Methods +; -------------------- +(super) @function + +; TODO: add method/call_expression to grammar and +; distinguish method call from variable access +(function_expression_body (identifier) @function) +; ((identifier)(selector (argument_part)) @function) + +; NOTE: This query is a bit of a work around for the fact that the dart grammar doesn't +; specifically identify a node as a function call +(((identifier) @function (#match? @function "^_?[a-z]")) + . (selector . (argument_part))) @function + +; Annotations +; -------------------- +(annotation + name: (identifier) @attribute) +(marker_annotation + name: (identifier) @attribute) + +; Operators and Tokens +; -------------------- +(template_substitution + "$" @punctuation.special + "{" @punctuation.special + "}" @punctuation.special +) @none + +(template_substitution + "$" @punctuation.special + (identifier_dollar_escaped) @variable +) @none + +(escape_sequence) @string.escape + +[ + "@" + "=>" + ".." + "??" + "==" + "?" + ":" + "&&" + "%" + "<" + ">" + "=" + ">=" + "<=" + "||" + (multiplicative_operator) + (increment_operator) + (is_operator) + (prefix_operator) + (equality_operator) + (additive_operator) +] @operator + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +; Delimiters +; -------------------- +[ + ";" + "." + "," +] @punctuation.delimiter + +; Types +; -------------------- +(class_definition + name: (identifier) @type) +(constructor_signature + name: (identifier) @type) +(scoped_identifier + scope: (identifier) @type) +(function_signature + name: (identifier) @method) +(getter_signature + (identifier) @method) +(setter_signature + name: (identifier) @method) +(enum_declaration + name: (identifier) @type) +(enum_constant + name: (identifier) @type) +(void_type) @type + +((scoped_identifier + scope: (identifier) @type + name: (identifier) @type) + (#match? @type "^[a-zA-Z]")) + +(type_identifier) @type + +(type_alias + (type_identifier) @type.definition) + +; Variables +; -------------------- +; var keyword +(inferred_type) @keyword + +((identifier) @type + (#match? @type "^_?[A-Z].*[a-z]")) ; catch Classes or IClasses not CLASSES + +("Function" @type) + +; properties +(unconditional_assignable_selector + (identifier) @property) + +(conditional_assignable_selector + (identifier) @property) + +; assignments +(assignment_expression + left: (assignable_expression) @variable) + +(this) @variable.builtin + +; Parameters +; -------------------- +(formal_parameter + name: (identifier) @parameter) + +(named_argument + (label (identifier) @parameter)) + +; Literals +; -------------------- +[ + (hex_integer_literal) + (decimal_integer_literal) + (decimal_floating_point_literal) + ; TODO: inaccessbile nodes + ; (octal_integer_literal) + ; (hex_floating_point_literal) +] @number + +(symbol_literal) @symbol +(string_literal) @string +(true) @boolean +(false) @boolean +(null_literal) @constant.builtin + +(documentation_comment) @comment +(comment) @comment + +; Keywords +; -------------------- +[ + "import" + "library" + "export" + "as" + "show" + "hide" +] @include + +; Reserved words (cannot be used as identifiers) +[ + ; TODO: + ; "rethrow" cannot be targeted at all and seems to be an invisible node + ; TODO: + ; the assert keyword cannot be specifically targeted + ; because the grammar selects the whole node or the content + ; of the assertion not just the keyword + ; assert + (case_builtin) + "late" + "required" + "extension" + "on" + "class" + "enum" + "extends" + "in" + "is" + "new" + "super" + "with" +] @keyword + +[ + "return" + "yield" +] @keyword.return + + +; Built in identifiers: +; alone these are marked as keywords +[ + "await" + "deferred" + "factory" + "get" + "implements" + "interface" + "library" + "operator" + "mixin" + "part" + "set" + "typedef" +] @keyword + +[ + (const_builtin) + (final_builtin) + "abstract" + "async" + "async*" + "covariant" + "dynamic" + "external" + "static" + "sync*" +] @type.qualifier + +; when used as an identifier: +((identifier) @variable.builtin + (#any-of? @variable.builtin + "abstract" + "as" + "covariant" + "deferred" + "dynamic" + "export" + "external" + "factory" + "Function" + "get" + "implements" + "import" + "interface" + "library" + "operator" + "mixin" + "part" + "set" + "static" + "typedef")) + +["if" "else" "switch" "default"] @conditional + +[ + "try" + "throw" + "catch" + "finally" + (break_statement) +] @exception + +["do" "while" "continue" "for"] @repeat + +; Error +(ERROR) @error diff --git a/queries/dart/indents.scm b/queries/dart/indents.scm new file mode 100644 index 000000000..e01cc238d --- /dev/null +++ b/queries/dart/indents.scm @@ -0,0 +1,27 @@ +[ + (class_body) + (function_body) + (function_expression_body) + (declaration (initializers)) + (switch_block) + (if_statement) + (formal_parameter_list) + (formal_parameter) + (list_literal) + (return_statement) + (arguments) +] @indent + +[ + "(" + ")" + "{" + "}" + "[" + "]" +] @branch + +; this one is for dedenting the else block +(if_statement (block) @branch) + +(comment) @ignore diff --git a/queries/dart/injections.scm b/queries/dart/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/dart/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/queries/dart/locals.scm b/queries/dart/locals.scm new file mode 100644 index 000000000..1013d4a92 --- /dev/null +++ b/queries/dart/locals.scm @@ -0,0 +1,8 @@ +(class_definition + body: (_) @scope) + + (block) @scope + + (try_statement) @scope + (catch_clause) @scope + (finally_clause) @scope diff --git a/runtime/queries/devicetree/folds.scm b/queries/devicetree/folds.scm similarity index 100% rename from runtime/queries/devicetree/folds.scm rename to queries/devicetree/folds.scm diff --git a/runtime/queries/devicetree/highlights.scm b/queries/devicetree/highlights.scm similarity index 53% rename from runtime/queries/devicetree/highlights.scm rename to queries/devicetree/highlights.scm index 74ec89af1..e3140a5da 100644 --- a/runtime/queries/devicetree/highlights.scm +++ b/queries/devicetree/highlights.scm @@ -1,12 +1,11 @@ -(comment) @comment @spell +(comment) @comment [ (preproc_include) (dtsi_include) -] @keyword.import +] @include (preproc_def) @constant.macro - (preproc_function_def) @function.macro [ @@ -23,39 +22,14 @@ (integer_literal) @number (identifier) @variable - -(node - (identifier) @module) - -(property - (identifier) @property) - -(node - label: (_) @label) - -(call_expression - (identifier) @function.macro) +(node (identifier) @namespace) +(property (identifier) @property) +(labeled_item (identifier) @label) +(call_expression (identifier) @function.macro) (reference) @label ; referencing labeled_item.identifier - (unit_address) @constant -"=" @operator - -[ - "(" - ")" - "[" - "]" - "{" - "}" - "<" - ">" -] @punctuation.bracket - -[ - ";" - ":" - "," - "@" -] @punctuation.delimiter +[ "=" ] @operator +[ "(" ")" "[" "]" "{" "}" "<" ">" ] @punctuation.bracket +[ ";" ":" "," "@" ] @punctuation.delimiter diff --git a/runtime/queries/devicetree/indents.scm b/queries/devicetree/indents.scm similarity index 50% rename from runtime/queries/devicetree/indents.scm rename to queries/devicetree/indents.scm index 9740060ca..cd7c8fcd6 100644 --- a/runtime/queries/devicetree/indents.scm +++ b/queries/devicetree/indents.scm @@ -2,11 +2,13 @@ (node) (property) (integer_cells) -] @indent.begin +] @indent [ "}" ">" -] @indent.branch +] @branch -(comment) @indent.ignore +[ + (comment) +] @ignore diff --git a/queries/devicetree/injections.scm b/queries/devicetree/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/devicetree/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/runtime/queries/devicetree/locals.scm b/queries/devicetree/locals.scm similarity index 65% rename from runtime/queries/devicetree/locals.scm rename to queries/devicetree/locals.scm index e33a81dfd..95b124bd1 100644 --- a/runtime/queries/devicetree/locals.scm +++ b/queries/devicetree/locals.scm @@ -1,4 +1,4 @@ [ (node) (integer_cells) -] @local.scope +]@scope diff --git a/queries/diff/highlights.scm b/queries/diff/highlights.scm new file mode 100644 index 000000000..4b9cbad60 --- /dev/null +++ b/queries/diff/highlights.scm @@ -0,0 +1,6 @@ +[(addition) (new_file)] @text.diff.add +[(deletion) (old_file)] @text.diff.delete + +(commit) @constant +(location) @attribute +(command) @function diff --git a/runtime/queries/dockerfile/highlights.scm b/queries/dockerfile/highlights.scm similarity index 67% rename from runtime/queries/dockerfile/highlights.scm rename to queries/dockerfile/highlights.scm index 72893f8b0..2d1840e66 100644 --- a/runtime/queries/dockerfile/highlights.scm +++ b/queries/dockerfile/highlights.scm @@ -36,33 +36,28 @@ (double_quoted_string) @string -[ - (heredoc_marker) - (heredoc_end) -] @label - -((heredoc_block - (heredoc_line) @string) - (#set! priority 90)) - (expansion [ "$" "{" "}" - ] @punctuation.special) + ] @punctuation.special +) ((variable) @constant (#lua-match? @constant "^[A-Z][A-Z_0-9]*$")) (arg_instruction - . - (unquoted_string) @property) + . (unquoted_string) @property) (env_instruction - (env_pair - . - (unquoted_string) @property)) + (env_pair . (unquoted_string) @property)) (expose_instruction (expose_port) @number) + +((stopsignal_instruction) @number + (#match? @number "[0-9][0-9]?$")) + +((stopsignal_instruction) @constant.builtin + (#match? @constant.builtin "SIG(ABRT|HUP|INT|KILL|QUIT|STOP|TERM|TSTP)$")) diff --git a/queries/dockerfile/injections.scm b/queries/dockerfile/injections.scm new file mode 100644 index 000000000..c1fdd3f99 --- /dev/null +++ b/queries/dockerfile/injections.scm @@ -0,0 +1,3 @@ +(comment) @comment + +(shell_command) @bash diff --git a/runtime/queries/dot/highlights.scm b/queries/dot/highlights.scm similarity index 69% rename from runtime/queries/dot/highlights.scm rename to queries/dot/highlights.scm index 75ad92271..d8b70a949 100644 --- a/runtime/queries/dot/highlights.scm +++ b/queries/dot/highlights.scm @@ -10,7 +10,6 @@ ] @keyword (string_literal) @string - (number_literal) @number [ @@ -34,16 +33,23 @@ (subgraph id: (id - (identifier) @module)) + (identifier) @namespace) +) (attribute name: (id - (identifier) @variable.member)) + (identifier) @field) +) (attribute value: (id - (identifier) @constant)) + (identifier) @constant) +) -(comment) @comment @spell +(comment) @comment -(preproc) @keyword.directive +(preproc) @preproc + +(comment) @spell + +(ERROR) @error diff --git a/queries/dot/injections.scm b/queries/dot/injections.scm new file mode 100644 index 000000000..529d04d4a --- /dev/null +++ b/queries/dot/injections.scm @@ -0,0 +1,2 @@ +(html_internal) @html +(comment) @comment diff --git a/queries/ebnf/highlights.scm b/queries/ebnf/highlights.scm new file mode 100644 index 000000000..416aaab68 --- /dev/null +++ b/queries/ebnf/highlights.scm @@ -0,0 +1,43 @@ +;;;; Simple tokens ;;;; +(terminal) @string.grammar + +(special_sequence) @string.special.grammar + +(integer) @number + +(comment) @comment + +;;;; Identifiers ;;;; + +; Allow different highlighting for specific casings +((identifier) @type + (#match? @type "^[A-Z]")) + +((identifier) @symbol + (#match? @symbol "^[a-z]")) + +((identifier) @constant + (#match? @constant "^[A-Z][A-Z0-9_]+$")) + +;;; Punctuation ;;;; +[ + ";" + "," +] @punctuation.delimiter + +[ + "|" + "*" + "-" +] @operator + +"=" @keyword.operator + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket diff --git a/runtime/queries/ecma/folds.scm b/queries/ecma/folds.scm similarity index 84% rename from runtime/queries/ecma/folds.scm rename to queries/ecma/folds.scm index a348f3444..50f235a5d 100644 --- a/runtime/queries/ecma/folds.scm +++ b/queries/ecma/folds.scm @@ -1,10 +1,9 @@ [ - (arguments) (for_in_statement) (for_statement) (while_statement) (arrow_function) - (function_expression) + (function) (function_declaration) (class_declaration) (method_definition) @@ -13,11 +12,10 @@ (switch_statement) (switch_case) (switch_default) - (import_statement)+ + (import_statement) (if_statement) (try_statement) (catch_clause) - (array) (object) (generator_function) (generator_function_declaration) diff --git a/queries/ecma/highlights.scm b/queries/ecma/highlights.scm new file mode 100644 index 000000000..1de0de302 --- /dev/null +++ b/queries/ecma/highlights.scm @@ -0,0 +1,276 @@ +; Types + +; Javascript + +; Variables +;----------- +(identifier) @variable + +; Properties +;----------- + +(property_identifier) @property +(shorthand_property_identifier) @property +(private_property_identifier) @property + +(variable_declarator + name: (object_pattern + (shorthand_property_identifier_pattern))) @variable + +; Special identifiers +;-------------------- + +((identifier) @constructor + (#lua-match? @constructor "^[A-Z]")) + +((identifier) @constant + (#lua-match? @constant "^[A-Z_][A-Z%d_]+$")) + +((shorthand_property_identifier) @constant + (#lua-match? @constant "^[A-Z_][A-Z%d_]+$")) + +((identifier) @variable.builtin + (#vim-match? @variable.builtin "^(arguments|module|console|window|document)$")) + +((identifier) @function.builtin + (#eq? @function.builtin "require")) + +; Function and method definitions +;-------------------------------- + +(function + name: (identifier) @function) +(function_declaration + name: (identifier) @function) +(generator_function + name: (identifier) @function) +(generator_function_declaration + name: (identifier) @function) +(method_definition + name: [(property_identifier) (private_property_identifier)] @method) + +(pair + key: (property_identifier) @method + value: (function)) +(pair + key: (property_identifier) @method + value: (arrow_function)) + +(assignment_expression + left: (member_expression + property: (property_identifier) @method) + right: (arrow_function)) +(assignment_expression + left: (member_expression + property: (property_identifier) @method) + right: (function)) + +(variable_declarator + name: (identifier) @function + value: (arrow_function)) +(variable_declarator + name: (identifier) @function + value: (function)) + +(assignment_expression + left: (identifier) @function + right: (arrow_function)) +(assignment_expression + left: (identifier) @function + right: (function)) + +; Function and method calls +;-------------------------- + +(call_expression + function: (identifier) @function.call) + +(call_expression + function: (member_expression + property: [(property_identifier) (private_property_identifier)] @method.call)) + +; Variables +;---------- +(namespace_import + (identifier) @namespace) + +; Literals +;--------- + +[ + (this) + (super) +] @variable.builtin + +[ + (true) + (false) +] @boolean + +[ + (null) + (undefined) +] @constant.builtin + +(comment) @comment + +(hash_bang_line) @preproc + +(comment) @spell + +(string) @string @spell +(template_string) @string +(escape_sequence) @string.escape +(regex_pattern) @string.regex +(regex "/" @punctuation.bracket) ; Regex delimiters + +(number) @number +((identifier) @number + (#any-of? @number "NaN" "Infinity")) + +; Punctuation +;------------ + +"..." @punctuation.special + +";" @punctuation.delimiter +"." @punctuation.delimiter +"," @punctuation.delimiter + +(pair ":" @punctuation.delimiter) +(pair_pattern ":" @punctuation.delimiter) + +[ + "--" + "-" + "-=" + "&&" + "+" + "++" + "+=" + "&=" + "/=" + "**=" + "<<=" + "<" + "<=" + "<<" + "=" + "==" + "===" + "!=" + "!==" + "=>" + ">" + ">=" + ">>" + "||" + "%" + "%=" + "*" + "**" + ">>>" + "&" + "|" + "^" + "??" + "*=" + ">>=" + ">>>=" + "^=" + "|=" + "&&=" + "||=" + "??=" +] @operator + +(binary_expression "/" @operator) +(ternary_expression ["?" ":"] @conditional.ternary) +(unary_expression ["!" "~" "-" "+"] @operator) +(unary_expression ["delete" "void" "typeof"] @keyword.operator) + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +((template_substitution ["${" "}"] @punctuation.special) @none) + +; Keywords +;---------- + +[ +"if" +"else" +"switch" +"case" +] @conditional + +[ +"import" +"from" +] @include + +(export_specifier "as" @include) +(import_specifier "as" @include) +(namespace_export "as" @include) +(namespace_import "as" @include) + +[ +"for" +"of" +"do" +"while" +"continue" +] @repeat + +[ +"async" +"await" +"break" +"class" +"const" +"debugger" +"export" +"extends" +"get" +"in" +"instanceof" +"let" +"set" +"static" +"target" +"typeof" +"var" +"with" +] @keyword + +[ +"return" +"yield" +] @keyword.return + +[ + "function" +] @keyword.function + +[ + "new" + "delete" +] @keyword.operator + +[ + "throw" + "try" + "catch" + "finally" +] @exception + +(export_statement + "default" @keyword) +(switch_default + "default" @conditional) diff --git a/queries/ecma/indents.scm b/queries/ecma/indents.scm new file mode 100644 index 000000000..0f99e0469 --- /dev/null +++ b/queries/ecma/indents.scm @@ -0,0 +1,56 @@ +[ + (arguments) + (array) + (binary_expression) + (class_body) + (export_clause) + (formal_parameters) + (named_imports) + (object) + (object_pattern) + (parenthesized_expression) + (return_statement) + (statement_block) + (switch_case) + (switch_default) + (switch_statement) + (template_substitution) + (ternary_expression) +] @indent + +(arguments (call_expression) @indent) +(binary_expression (call_expression) @indent) +(expression_statement (call_expression) @indent) +(arrow_function + body: (_) @_body + (#not-has-type? @_body statement_block) +) @indent +(assignment_expression + right: (_) @_right + (#not-has-type? @_right arrow_function function) +) @indent +(variable_declarator + value: (_) @_value + (#not-has-type? @_value arrow_function call_expression function) +) @indent + +(arguments ")" @indent_end) +(object "}" @indent_end) +(statement_block "}" @indent_end) + +[ + (arguments (object)) + ")" + "}" + "]" +] @branch +(statement_block "{" @branch) + +["}" "]"] @indent_end + +[ + (comment) + (template_string) +] @ignore + +(ERROR) @auto diff --git a/queries/ecma/injections.scm b/queries/ecma/injections.scm new file mode 100644 index 000000000..6bd5da862 --- /dev/null +++ b/queries/ecma/injections.scm @@ -0,0 +1,69 @@ +(((comment) @_jsdoc_comment + (#match? @_jsdoc_comment "^/\\*\\*[^\\*].*\\*/")) @jsdoc) + +(comment) @comment + +(call_expression + function: ((identifier) @language) + arguments: ((template_string) @content + (#offset! @content 0 1 0 -1))) + +(call_expression + function: ((identifier) @_name + (#eq? @_name "gql")) + arguments: ((template_string) @graphql + (#offset! @graphql 0 1 0 -1))) + +(call_expression + function: ((identifier) @_name + (#eq? @_name "hbs")) + arguments: ((template_string) @glimmer + (#offset! @glimmer 0 1 0 -1))) + +((glimmer_template) @glimmer) + +; styled.div`` +(call_expression + function: (member_expression + object: (identifier) @_name + (#eq? @_name "styled")) + arguments: ((template_string) @css + (#offset! @css 0 1 0 -1))) + +; styled(Component)`` +(call_expression + function: (call_expression + function: (identifier) @_name + (#eq? @_name "styled")) + arguments: ((template_string) @css + (#offset! @css 0 1 0 -1))) + +; styled.div.attrs({ prop: "foo" })`` +(call_expression + function: (call_expression + function: (member_expression + object: (member_expression + object: (identifier) @_name + (#eq? @_name "styled")))) + arguments: ((template_string) @css + (#offset! @css 0 1 0 -1))) + + +; styled(Component).attrs({ prop: "foo" })`` +(call_expression + function: (call_expression + function: (member_expression + object: (call_expression + function: (identifier) @_name + (#eq? @_name "styled")))) + arguments: ((template_string) @css + (#offset! @css 0 1 0 -1))) + +(regex_pattern) @regex + +((comment) @_gql_comment + (#eq? @_gql_comment "/* GraphQL */") + (template_string) @graphql) + +(((template_string) @_template_string + (#match? @_template_string "^`#graphql")) @graphql) diff --git a/queries/ecma/locals.scm b/queries/ecma/locals.scm new file mode 100644 index 000000000..4c035d269 --- /dev/null +++ b/queries/ecma/locals.scm @@ -0,0 +1,37 @@ +; Scopes +;------- + +(statement_block) @scope +(function) @scope +(arrow_function) @scope +(function_declaration) @scope +(method_definition) @scope +(for_statement) @scope +(for_in_statement) @scope +(catch_clause) @scope + +; Definitions +;------------ + +(variable_declarator + name: (identifier) @definition.var) + +(import_specifier + (identifier) @definition.import) + +(namespace_import + (identifier) @definition.import) + +(function_declaration + ((identifier) @definition.function) + (#set! definition.var.scope parent)) + +(method_definition + ((property_identifier) @definition.function) + (#set! definition.var.scope parent)) + +; References +;------------ + +(identifier) @reference +(shorthand_property_identifier) @reference diff --git a/runtime/queries/eex/highlights.scm b/queries/eex/highlights.scm similarity index 65% rename from runtime/queries/eex/highlights.scm rename to queries/eex/highlights.scm index d032a7486..781b39466 100644 --- a/runtime/queries/eex/highlights.scm +++ b/queries/eex/highlights.scm @@ -9,4 +9,7 @@ ] @tag.delimiter ; EEx comments are highlighted as such -(comment) @comment @spell +(comment) @comment + +; Tree-sitter parser errors +(ERROR) @error diff --git a/queries/eex/injections.scm b/queries/eex/injections.scm new file mode 100644 index 000000000..f43206f55 --- /dev/null +++ b/queries/eex/injections.scm @@ -0,0 +1,5 @@ +; EEx expressions are Elixir +(expression) @elixir + +; EEx expressions can span multiple interpolated lines +(partial_expression) @elixir @combined diff --git a/runtime/queries/elixir/folds.scm b/queries/elixir/folds.scm similarity index 85% rename from runtime/queries/elixir/folds.scm rename to queries/elixir/folds.scm index 7abfe6797..b99a6d9e0 100644 --- a/runtime/queries/elixir/folds.scm +++ b/queries/elixir/folds.scm @@ -1,6 +1,5 @@ [ (anonymous_function) - (stab_clause) (arguments) (block) (do_block) diff --git a/queries/elixir/highlights.scm b/queries/elixir/highlights.scm new file mode 100644 index 000000000..c3aee40c7 --- /dev/null +++ b/queries/elixir/highlights.scm @@ -0,0 +1,227 @@ +; Punctuation +[ + "," + ";" +] @punctuation.delimiter + +[ + "(" + ")" + "<<" + ">>" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +[ + "%" +] @punctuation.special + +; Parser Errors +(ERROR) @error + +; Identifiers +(identifier) @variable + +; Unused Identifiers +((identifier) @comment (#match? @comment "^_")) + +; Comments +(comment) @comment +(comment) @spell + +; Strings +(string) @string +(string) @spell + +; Modules +(alias) @type + +; Atoms & Keywords +[ + (atom) + (quoted_atom) + (keyword) + (quoted_keyword) +] @symbol + +; Interpolation +(interpolation ["#{" "}"] @string.special) + +; Escape sequences +(escape_sequence) @string.escape + +; Integers +(integer) @number + +; Floats +(float) @float + +; Characters +[ + (char) + (charlist) +] @character + +; Booleans +(boolean) @boolean + +; Nil +(nil) @constant.builtin + +; Operators +(operator_identifier) @operator + +(unary_operator operator: _ @operator) + +(binary_operator operator: _ @operator) + +; Pipe Operator +(binary_operator operator: "|>" right: (identifier) @function) + +(dot operator: _ @operator) + +(stab_clause operator: _ @operator) + +; Local Function Calls +(call target: (identifier) @function.call) + +; Remote Function Calls +(call target: (dot left: [ + (atom) @type + (_) +] right: (identifier) @function.call) (arguments)) + +; Definition Function Calls +(call target: ((identifier) @keyword.function (#any-of? @keyword.function + "def" + "defdelegate" + "defexception" + "defguard" + "defguardp" + "defimpl" + "defmacro" + "defmacrop" + "defmodule" + "defn" + "defnp" + "defoverridable" + "defp" + "defprotocol" + "defstruct" +)) (arguments [ + (identifier) @function + (binary_operator left: (identifier) @function operator: "when")])?) + +; Kernel Keywords & Special Forms +(call target: ((identifier) @keyword (#any-of? @keyword + "alias" + "case" + "catch" + "cond" + "else" + "for" + "if" + "import" + "quote" + "raise" + "receive" + "require" + "reraise" + "super" + "throw" + "try" + "unless" + "unquote" + "unquote_splicing" + "use" + "with" +))) + +; Special Constants +((identifier) @constant.builtin (#any-of? @constant.builtin + "__CALLER__" + "__DIR__" + "__ENV__" + "__MODULE__" + "__STACKTRACE__" +)) + +; Reserved Keywords +[ + "after" + "catch" + "do" + "end" + "fn" + "rescue" + "when" + "else" +] @keyword + +; Operator Keywords +[ + "and" + "in" + "not in" + "not" + "or" +] @keyword.operator + +; Capture Operator +(unary_operator + operator: "&" + operand: [ + (integer) @operator + (binary_operator + left: [ + (call target: (dot left: (_) right: (identifier) @function)) + (identifier) @function + ] operator: "/" right: (integer) @operator) + ]) + +; Non-String Sigils +(sigil + "~" @string.special + ((sigil_name) @string.special) @_sigil_name + quoted_start: _ @string.special + quoted_end: _ @string.special + ((sigil_modifiers) @string.special)? + (#not-any-of? @_sigil_name "s" "S")) + +; String Sigils +(sigil + "~" @string + ((sigil_name) @string) @_sigil_name + quoted_start: _ @string + (quoted_content) @string + quoted_end: _ @string + ((sigil_modifiers) @string)? + (#any-of? @_sigil_name "s" "S")) + +; Module attributes +(unary_operator + operator: "@" + operand: [ + (identifier) + (call target: (identifier)) + ] @constant) @constant + +; Documentation +(unary_operator + operator: "@" + operand: (call + target: ((identifier) @_identifier (#any-of? @_identifier "moduledoc" "typedoc" "shortdoc" "doc")) @comment + (arguments [ + (string) + (boolean) + (charlist) + (sigil + "~" @comment + ((sigil_name) @comment) + quoted_start: _ @comment + (quoted_content) @comment + quoted_end: _ @comment) + ] @comment))) @comment diff --git a/runtime/queries/elixir/indents.scm b/queries/elixir/indents.scm similarity index 62% rename from runtime/queries/elixir/indents.scm rename to queries/elixir/indents.scm index 5470b6422..517f66940 100644 --- a/runtime/queries/elixir/indents.scm +++ b/queries/elixir/indents.scm @@ -6,7 +6,7 @@ (stab_clause) (tuple) (arguments) -] @indent.begin +] @indent [ ")" @@ -17,9 +17,7 @@ "rescue" "}" "end" -] @indent.end @indent.branch +] @indent_end @branch ; Elixir pipelines are not indented, but other binary operator chains are -((binary_operator - operator: _ @_operator) @indent.begin - (#not-eq? @_operator "|>")) +((binary_operator operator: _ @_operator) @indent (#not-eq? @_operator "|>")) diff --git a/queries/elixir/injections.scm b/queries/elixir/injections.scm new file mode 100644 index 000000000..423fddea7 --- /dev/null +++ b/queries/elixir/injections.scm @@ -0,0 +1,48 @@ +; Comments +(comment) @comment + +; Documentation +(unary_operator + operator: "@" + operand: (call + target: ((identifier) @_identifier (#any-of? @_identifier "moduledoc" "typedoc" "shortdoc" "doc")) + (arguments [ + (string (quoted_content) @markdown) + (sigil (quoted_content) @markdown) + ]))) + +; HEEx +(sigil + (sigil_name) @_sigil_name + (quoted_content) @heex +(#eq? @_sigil_name "H")) + +; Surface +(sigil + (sigil_name) @_sigil_name + (quoted_content) @surface +(#eq? @_sigil_name "F")) + +; Zigler +(sigil + (sigil_name) @_sigil_name + (quoted_content) @eex +(#any-of? @_sigil_name "E" "L")) + +(sigil + (sigil_name) @_sigil_name + (quoted_content) @zig +(#any-of? @_sigil_name "z" "Z")) + +; Regex +(sigil + (sigil_name) @_sigil_name + (quoted_content) @regex +(#any-of? @_sigil_name "r" "R")) + +; Jason +(sigil + (sigil_name) @_sigil_name + (quoted_content) @json +(#any-of? @_sigil_name "j" "J")) + diff --git a/queries/elixir/locals.scm b/queries/elixir/locals.scm new file mode 100644 index 000000000..79a9676df --- /dev/null +++ b/queries/elixir/locals.scm @@ -0,0 +1,164 @@ +; References +(identifier) @reference +(alias) @reference + +; Module Definitions +(call + target: ((identifier) @_identifier (#eq? @_identifier "defmodule")) + (arguments (alias) @definition.type)) + +; Pattern Match Definitions +(binary_operator left: [ + (identifier) @definition.var + (_ (identifier) @definition.var) + (_ (_ (identifier) @definition.var)) + (_ (_ (_ (identifier) @definition.var))) + (_ (_ (_ (_ (identifier) @definition.var)))) + (_ (_ (_ (_ (_ (identifier) @definition.var))))) + (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))) + (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))))))))) +] operator: "=") + +; Stab Clause Definitions +(stab_clause + left: [ + (arguments [ + (identifier) @definition.var + (_ (identifier) @definition.var) + (_ (_ (identifier) @definition.var)) + (_ (_ (_ (identifier) @definition.var))) + (_ (_ (_ (_ (identifier) @definition.var)))) + (_ (_ (_ (_ (_ (identifier) @definition.var))))) + (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))) + (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))))))))) + ]) + (binary_operator + left: (arguments [ + (identifier) @definition.var + (_ (identifier) @definition.var) + (_ (_ (identifier) @definition.var)) + (_ (_ (_ (identifier) @definition.var))) + (_ (_ (_ (_ (identifier) @definition.var)))) + (_ (_ (_ (_ (_ (identifier) @definition.var))))) + (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))) + (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var))))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.var)))))))))))))))))))) + ]) operator: "when") +]) + +; Aliases +(call + target: ((identifier) @_identifier (#any-of? @_identifier "require" "alias" "use" "import")) + (arguments [ + (alias) @definition.import + (_ (alias) @definition.import) + (_ (_ (alias) @definition.import)) + (_ (_ (_ (alias) @definition.import))) + (_ (_ (_ (_ (alias) @definition.import)))) + ] +)) + +; Local Function Definitions & Scopes +(call + target: ((identifier) @_identifier (#any-of? @_identifier "def" "defp" "defmacro" "defmacrop" "defguard" "defguardp" "defn" "defnp" "for")) + (arguments [ + (identifier) @definition.function + (binary_operator left: (identifier) @definition.function operator: "when") + (binary_operator (identifier) @definition.parameter) + (call target: (identifier) @definition.function (arguments [ + (identifier) @definition.parameter + (_ (identifier) @definition.parameter) + (_ (_ (identifier) @definition.parameter)) + (_ (_ (_ (identifier) @definition.parameter))) + (_ (_ (_ (_ (identifier) @definition.parameter)))) + (_ (_ (_ (_ (_ (identifier) @definition.parameter))))) + (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))) + (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))))))))))))) + ])) + ]?) (#set! definition.function.scope parent) + (do_block)? +) @scope + +; ExUnit Test Definitions & Scopes +(call + target: ((identifier) @_identifier (#eq? @_identifier "test")) + (arguments [ + (string) + ((string) . "," . [ + (identifier) @definition.parameter + (_ (identifier) @definition.parameter) + (_ (_ (identifier) @definition.parameter)) + (_ (_ (_ (identifier) @definition.parameter))) + (_ (_ (_ (_ (identifier) @definition.parameter)))) + (_ (_ (_ (_ (_ (identifier) @definition.parameter))))) + (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))) + (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter))))))))))))))))))) + (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (_ (identifier) @definition.parameter)))))))))))))))))))) + ]) +]) (do_block)?) @scope + +; Stab Clause Scopes +(stab_clause) @scope diff --git a/queries/elm/highlights.scm b/queries/elm/highlights.scm new file mode 100644 index 000000000..63514eb3e --- /dev/null +++ b/queries/elm/highlights.scm @@ -0,0 +1,98 @@ +[(line_comment) (block_comment)] @comment + +; Keywords +[ + "if" + "then" + "else" + (case) + (of) +] @conditional + +[ + "let" + "in" + (as) + (port) + (exposing) + (alias) + (infix) + (module) +] @keyword + +[ + (double_dot) + "|" +] @punctuation.special +[ + "," + (dot) +] @punctuation.delimiter + +[ + "(" + ")" + "{" + "}" +] @punctuation.bracket + +(type_annotation + (lower_case_identifier) @function) +(port_annotation + (lower_case_identifier) @function) +(function_declaration_left + (lower_case_identifier) @function) +(function_call_expr + target: (value_expr) @function) + +(value_qid (upper_case_identifier) @constructor) +(value_qid ((dot) (lower_case_identifier) @field)) +(field_access_expr ((dot) (lower_case_identifier) @field)) + +(lower_pattern) @parameter +(record_base_identifier) @method + +[ + (backslash) + (underscore) +] @function + +[ + (operator_identifier) + (eq) + (colon) + (arrow) +] @operator + +(import) @include + +(number_constant_expr) @number + +(type) @keyword + +(module_declaration + (upper_case_qid (upper_case_identifier)) @constructor) +(type_declaration + (upper_case_identifier) @constructor) +(type_ref) @type +(type_alias_declaration + name: (upper_case_identifier) @type.definition) +(field_type name: + (lower_case_identifier) @property) + +(union_variant + (upper_case_identifier) @symbol) +(union_pattern) @symbol +(value_expr + (upper_case_qid (upper_case_identifier)) @symbol) + +; strings +(string_escape) @string +(open_quote) @string +(close_quote) @string +(regular_string_part) @string + +[ + (open_char) + (close_char) +] @character diff --git a/queries/elm/injections.scm b/queries/elm/injections.scm new file mode 100644 index 000000000..6395776e1 --- /dev/null +++ b/queries/elm/injections.scm @@ -0,0 +1,3 @@ +[(line_comment) (block_comment)] @comment + +(glsl_content) @glsl diff --git a/queries/elvish/highlights.scm b/queries/elvish/highlights.scm new file mode 100644 index 000000000..af7c41dd8 --- /dev/null +++ b/queries/elvish/highlights.scm @@ -0,0 +1,70 @@ +(comment) @comment + +["if" "elif"] @conditional +(if (else "else" @conditional)) + +["while" "for"] @repeat +(while (else "else" @repeat)) +(for (else "else" @repeat)) + +["try" "catch" "finally"] @exception +(try (else "else" @exception)) + +"use" @include +(import (bareword) @string.special) + +(wildcard ["*" "**" "?"] @character.special) + +(command argument: (bareword) @parameter) +(command head: (identifier) @function.call) +((command head: (identifier) @keyword.return) + (#eq? @keyword.return "return")) +((command (identifier) @keyword.operator) + (#any-of? @keyword.operator "and" "or" "coalesce")) +[ + "+" "-" "*" "/" "%" "<" "<=""==" "!=" ">" + ">=" "s" ">=s" +] @function.builtin + +[">" "<" ">>" "<>" "|"] @operator + +(io_port) @number + +(function_definition + "fn" @keyword.function + (identifier) @function) + +(parameter_list) @parameter +(parameter_list "|" @punctuation.bracket) + +["var" "set" "tmp" "del"] @keyword +(variable_declaration + (lhs (identifier) @variable)) + +(variable_assignment + (lhs (identifier) @variable)) + +(temporary_assignment + (lhs (identifier) @variable)) + +(variable_deletion + (identifier) @variable) + + +(number) @number +(string) @string + +(variable (identifier) @variable) +((variable (identifier) @function) + (#match? @function ".+\\~$")) +((variable (identifier) @boolean) + (#any-of? @boolean "true" "false")) +((variable (identifier) @constant.builtin) + (#any-of? @constant.builtin + "_" "after-chdir" "args" "before-chdir" "buildinfo" "nil" + "notify-bg-job-success" "num-bg-jobs" "ok" "paths" "pid" + "pwd" "value-out-indicator" "version")) + +["$" "@"] @punctuation.special +["(" ")" "[" "]" "{" "}"] @punctuation.bracket +";" @punctuation.delimiter diff --git a/queries/elvish/injections.scm b/queries/elvish/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/elvish/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/runtime/queries/embedded_template/highlights.scm b/queries/embedded_template/highlights.scm similarity index 67% rename from runtime/queries/embedded_template/highlights.scm rename to queries/embedded_template/highlights.scm index 410983d65..0bf76a7d4 100644 --- a/runtime/queries/embedded_template/highlights.scm +++ b/queries/embedded_template/highlights.scm @@ -1,4 +1,4 @@ -(comment_directive) @comment @spell +(comment_directive) @comment [ "<%#" diff --git a/queries/embedded_template/injections.scm b/queries/embedded_template/injections.scm new file mode 100644 index 000000000..d55c87e09 --- /dev/null +++ b/queries/embedded_template/injections.scm @@ -0,0 +1,2 @@ +(content) @html @combined +(code) @ruby @combined diff --git a/runtime/queries/erlang/folds.scm b/queries/erlang/folds.scm similarity index 88% rename from runtime/queries/erlang/folds.scm rename to queries/erlang/folds.scm index 65c2d8ed1..35073e869 100644 --- a/runtime/queries/erlang/folds.scm +++ b/queries/erlang/folds.scm @@ -2,7 +2,6 @@ (fun_decl) (anonymous_fun) (case_expr) - (maybe_expr) (map_expr) (export_attribute) (export_type_attribute) diff --git a/queries/erlang/highlights.scm b/queries/erlang/highlights.scm new file mode 100644 index 000000000..fba44359f --- /dev/null +++ b/queries/erlang/highlights.scm @@ -0,0 +1,124 @@ +((atom) @constant (#set! "priority" "90")) +(var) @variable + +(char) @character +(integer) @number +(float) @float + +(comment) @comment + +;; keyword +[ + "fun" + "div" +] @keyword + +;; bracket +[ + "(" + ")" + "{" + "}" + "[" + "]" + "#" +] @punctuation.bracket + +;;; Comparisons +[ + "==" + "=:=" + "=/=" + "=<" + ">=" + "<" + ">" +] @operator ;; .comparison + +;;; operator +[ + ":" + ":=" + "!" + ;; "-" + "+" + "=" + "->" + "=>" + "|" +] @operator + +[ + "," + "." + ";" +] @punctuation.delimiter + +;; conditional +([ + "receive" + "if" + "case" + "of" + "when" + "after" + "end" +] @conditional (#set! "priority" 95)) + +[ + "catch" + "try" +] @exception + +((atom) @boolean (#any-of? @boolean "true" "false")) + +;; Macros +((macro_call_expr) @constant.macro (#set! "priority" 101)) + +;; Preprocessor +(pp_define + lhs: _ @constant.macro (#set! "priority" 101) +) +(_preprocessor_directive) @preproc (#set! "priority" 99) + +;; Attributes +(pp_include) @include +(pp_include_lib) @include +(export_attribute) @include +(export_type_attribute) @type.definition +(export_type_attribute types: (fa fun: _ @type (#set! "priority" 101))) +(behaviour_attribute) @include +(module_attribute (atom) @namespace) @include +(wild_attribute name: (attr_name name: _ @attribute)) @attribute + +;; Records +(record_expr) @type +(record_field_expr _ @field) @type +(record_field_name _ @field) @type +(record_name "#" @type name: _ @type) @type +(record_decl name: _ @type) @type.definition +(record_field name: _ @field) +(record_field name: _ @field ty: _ @type) + +;; Type alias +(type_alias name: _ @type) @type.definition +(spec) @type.definition + +(comment) @comment +[(string) (binary)] @string + +;;; expr_function_call +(call expr: [(atom) (remote) (var)] @function) +(call (atom) @exception (#any-of? @exception "error" "throw" "exit")) + +;;; Parenthesized expression: (SomeFunc)(), only highlight the parens +(call + expr: (paren_expr "(" @function.call ")" @function.call) +) + +;;; function +(external_fun) @function.call +(internal_fun fun: (atom) @function.call) +(function_clause name: (atom) @function) +(fa fun: (atom) @function) + diff --git a/queries/fennel/highlights.scm b/queries/fennel/highlights.scm new file mode 100644 index 000000000..7322e55c3 --- /dev/null +++ b/queries/fennel/highlights.scm @@ -0,0 +1,121 @@ +(comment) @comment + +[ + "(" + ")" + "{" + "}" + "[" + "]" +] @punctuation.bracket + +[ + ":" + ":until" + "&" + "&as" + "?" +] @punctuation.special + +(nil) @constant.builtin +(vararg) @punctuation.special + +(boolean) @boolean +(number) @number + +(string) @string +(escape_sequence) @string.escape + +(symbol) @variable + +(multi_symbol + "." @punctuation.delimiter + (symbol) @field) + +(multi_symbol_method + ":" @punctuation.delimiter + (symbol) @method .) + +(list . (symbol) @function) +(list . (multi_symbol (symbol) @function .)) + +((symbol) @variable.builtin + (#match? @variable.builtin "^[$]")) + +(binding) @symbol + +[ + "fn" + "lambda" + "hashfn" + "#" +] @keyword.function + +(fn name: [ + (symbol) @function + (multi_symbol (symbol) @function .) +]) + +(lambda name: [ + (symbol) @function + (multi_symbol (symbol) @function .) +]) + +[ + "for" + "each" +] @repeat +((symbol) @repeat + (#any-of? @repeat + "while")) + +[ + "match" +] @conditional +((symbol) @conditional + (#any-of? @conditional + "if" "when")) + +[ + "global" + "local" + "let" + "set" + "var" + "where" + "or" +] @keyword +((symbol) @keyword + (#any-of? @keyword + "comment" "do" "doc" "eval-compiler" "lua" "macros" "quote" "tset" "values")) + +((symbol) @include + (#any-of? @include + "require" "require-macros" "import-macros" "include")) + +[ + "collect" + "icollect" + "accumulate" +] @function.macro + +((symbol) @function.macro + (#any-of? @function.macro + "->" "->>" "-?>" "-?>>" "?." "doto" "macro" "macrodebug" "partial" "pick-args" + "pick-values" "with-open")) + +; Lua builtins +((symbol) @constant.builtin + (#any-of? @constant.builtin + "arg" "_ENV" "_G" "_VERSION")) + +((symbol) @function.builtin + (#any-of? @function.builtin + "assert" "collectgarbage" "dofile" "error" "getmetatable" "ipairs" + "load" "loadfile" "next" "pairs" "pcall" "print" "rawequal" "rawget" + "rawlen" "rawset" "require" "select" "setmetatable" "tonumber" "tostring" + "type" "warn" "xpcall")) + +((symbol) @function.builtin + (#any-of? @function.builtin + "loadstring" "module" "setfenv" "unpack")) diff --git a/queries/fennel/injections.scm b/queries/fennel/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/fennel/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/queries/fennel/locals.scm b/queries/fennel/locals.scm new file mode 100644 index 000000000..3018732f9 --- /dev/null +++ b/queries/fennel/locals.scm @@ -0,0 +1,26 @@ +[ + (program) + (fn) + (lambda) + (let) + (each) + (for) + (match) +] @scope + +( + (list . (symbol) @_special) @scope + (#any-of? @_special + "while" "if" "when" "do" "collect" "icollect" "accumulate") +) + +(fn name: (symbol) @definition.function + (#set! definition.function.scope "parent")) +(lambda name: (symbol) @definition.function + (#set! definition.function.scope "parent")) + +; TODO: use @definition.parameter for parameters +(binding (symbol) @definition.var) +(for_clause . (symbol) @definition.var) + +(symbol) @reference diff --git a/queries/fish/folds.scm b/queries/fish/folds.scm new file mode 100644 index 000000000..6075e2e04 --- /dev/null +++ b/queries/fish/folds.scm @@ -0,0 +1,8 @@ +[ + (function_definition) + (if_statement) + (switch_statement) + (for_statement) + (while_statement) + (begin_statement) +] @fold diff --git a/queries/fish/highlights.scm b/queries/fish/highlights.scm new file mode 100644 index 000000000..505726819 --- /dev/null +++ b/queries/fish/highlights.scm @@ -0,0 +1,169 @@ +;; Fish highlighting + +;; Operators + +[ + "&&" + "||" + "|" + "&" + ".." + "!" + (direction) + (stream_redirect) +] @operator + +;; match operators of test command +(command + name: (word) @function.builtin (#match? @function.builtin "^test$") + argument: (word) @operator (#match? @operator "^(!?\\=|-[a-zA-Z]+)$")) + +;; match operators of [ command +(test_command + argument: (word) @operator (#match? @operator "^(!?\\=|-[a-zA-Z]+)$")) + +[ + "not" + "and" + "or" +] @keyword.operator + +;; Conditionals + +(if_statement +[ + "if" + "end" +] @conditional) + +(switch_statement +[ + "switch" + "end" +] @conditional) + +(case_clause +[ + "case" +] @conditional) + +(else_clause +[ + "else" +] @conditional) + +(else_if_clause +[ + "else" + "if" +] @conditional) + +;; Loops/Blocks + +(while_statement +[ + "while" + "end" +] @repeat) + +(for_statement +[ + "for" + "end" +] @repeat) + +(begin_statement +[ + "begin" + "end" +] @repeat) + +;; Keywords + +[ + "in" + (break) + (continue) +] @keyword + +"return" @keyword.return + +;; Punctuation + +[ + "[" + "]" + "{" + "}" + "(" + ")" +] @punctuation.bracket + +"," @punctuation.delimiter + +;; Commands + +(command + argument: [ + (word) @parameter (#match? @parameter "^-") + ] +) + +(command_substitution "$" @punctuation.bracket) + +; non-bultin command names +(command name: (word) @function.call) + +; derived from builtin -n (fish 3.2.2) +(command + name: [ + (word) @function.builtin + (#any-of? @function.builtin "." ":" "_" "alias" "argparse" "bg" "bind" "block" "breakpoint" "builtin" "cd" "command" "commandline" "complete" "contains" "count" "disown" "echo" "emit" "eval" "exec" "exit" "fg" "functions" "history" "isatty" "jobs" "math" "printf" "pwd" "random" "read" "realpath" "set" "set_color" "source" "status" "string" "test" "time" "type" "ulimit" "wait") + ] +) + +(test_command (word) @function.builtin) + +;; Functions + +(function_definition ["function" "end"] @keyword.function) + +(function_definition + name: [ + (word) (concatenation) + ] +@function) + +(function_definition + option: [ + (word) + (concatenation (word)) + ] @parameter (#match? @parameter "^-") +) + +;; Strings + +[(double_quote_string) (single_quote_string)] @string +(escape_sequence) @string.escape + +;; Variables + +(variable_name) @variable +(variable_expansion) @constant + +;; Nodes + +[(integer) (float)] @number +(comment) @comment +(comment) @spell + +((word) @boolean +(#any-of? @boolean "true" "false")) + +((program . (comment) @preproc) + (#match? @preproc "^#!/")) + +;; Error + +(ERROR) @error + diff --git a/queries/fish/indents.scm b/queries/fish/indents.scm new file mode 100644 index 000000000..cf8d62658 --- /dev/null +++ b/queries/fish/indents.scm @@ -0,0 +1,16 @@ +[ + (function_definition) + (while_statement) + (for_statement) + (if_statement) + (begin_statement) + (switch_statement) +] @indent + +[ + (else_if_clause) + (else_clause) + "end" +] @branch + +(comment) @ignore diff --git a/queries/fish/injections.scm b/queries/fish/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/fish/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/runtime/queries/fish/locals.scm b/queries/fish/locals.scm similarity index 50% rename from runtime/queries/fish/locals.scm rename to queries/fish/locals.scm index 904d568f9..a522c78dc 100644 --- a/runtime/queries/fish/locals.scm +++ b/queries/fish/locals.scm @@ -1,4 +1,4 @@ -; Scopes +;; Scopes [ (command) (function_definition) @@ -7,13 +7,12 @@ (begin_statement) (while_statement) (switch_statement) -] @local.scope +] @scope -; Definitions +;; Definitions (function_definition - name: (word) @local.definition.function) + name: (word) @definition.function) -; References -(variable_name) @local.reference - -(word) @local.reference +;; References +(variable_name) @reference +(word) @reference diff --git a/queries/foam/folds.scm b/queries/foam/folds.scm new file mode 100644 index 000000000..2e499c2e2 --- /dev/null +++ b/queries/foam/folds.scm @@ -0,0 +1,7 @@ +[ + (comment) + (list) + (dict_core) +] @fold + +(code (code_body)* @fold) diff --git a/queries/foam/highlights.scm b/queries/foam/highlights.scm new file mode 100644 index 000000000..86a3bf324 --- /dev/null +++ b/queries/foam/highlights.scm @@ -0,0 +1,69 @@ +;; Comments +(comment) @comment + +;; Generic Key-value pairs and dictionary keywords +(key_value + keyword: (identifier) @function +) +(dict + key: (identifier) @type +) + +;; Macros +(macro + "$" @conditional + (prev_scope)* @conditional + (identifier)* @namespace +) + + +;; Directives +"#" @conditional +(preproc_call + directive: (identifier)* @conditional + argument: (identifier)* @namespace +) +( + (preproc_call + argument: (identifier)* @namespace + ) @conditional + (#match? @conditional "ifeq") +) +( + (preproc_call) @conditional + (#match? @conditional "(else|endif)") +) + +;; Literal numbers and strings +(number_literal) @float +(string_literal) @string +(escape_sequence) @string.escape + +;; Treat [m^2 s^-2] the same as if it was put in numbers format +(dimensions dimension: (identifier) @float) + +;; Punctuation +[ + "(" + ")" + "[" + "]" + "{" + "}" + "#{" + "#}" + "|-" + "-|" + "" + "$$" +] @punctuation.bracket + +[ + ";" +] @punctuation.delimiter + +;; Special identifiers +([(identifier) "on" "off" "true" "false" "yes" "no"] @constant.builtin +(#match? @constant.builtin "^(uniform|non-uniform|and|or|on|off|true|false|yes|no)$") +) diff --git a/queries/foam/indents.scm b/queries/foam/indents.scm new file mode 100644 index 000000000..033700c17 --- /dev/null +++ b/queries/foam/indents.scm @@ -0,0 +1,11 @@ +[ + "{" + "}" +] @branch + +[(dict) (key_value)] @indent + + +[ + (comment) +] @ignore diff --git a/queries/foam/injections.scm b/queries/foam/injections.scm new file mode 100644 index 000000000..4afdb63b0 --- /dev/null +++ b/queries/foam/injections.scm @@ -0,0 +1,12 @@ +;; Pass code blocks to Cpp highlighter +(code (code_body) @cpp) + +;; Pass identifiers to Go highlighter (Cheating I know) +;;((identifier) @lua) + +;; Highlight regex syntax inside literal strings +((string_literal) @regex) + +;; Highlight PyFoam syntax as Python statements +(pyfoam_variable code_body: (_) @python) +(pyfoam_expression code_body: (_) @python) diff --git a/queries/foam/locals.scm b/queries/foam/locals.scm new file mode 100644 index 000000000..2abe743dd --- /dev/null +++ b/queries/foam/locals.scm @@ -0,0 +1,6 @@ +(dict) @scope + +(dict key: (_) @definition.type) + +(key_value keyword: (_) @definition.parameter) +(key_value value: (macro (identifier)*)* @reference) diff --git a/queries/fortran/folds.scm b/queries/fortran/folds.scm new file mode 100644 index 000000000..a2edc64d3 --- /dev/null +++ b/queries/fortran/folds.scm @@ -0,0 +1,11 @@ +;; by @oponkork +[ + (if_statement) + (where_statement) + (enum_statement) + (do_loop_statement) + (derived_type_definition) + (function) + (subroutine) + (interface) +] @fold diff --git a/queries/fortran/highlights.scm b/queries/fortran/highlights.scm new file mode 100644 index 000000000..09cf63ca5 --- /dev/null +++ b/queries/fortran/highlights.scm @@ -0,0 +1,185 @@ +(identifier) @variable +(string_literal) @string +(number_literal) @number +(boolean_literal) @boolean +(comment) @comment + +[ + (intrinsic_type) + "pointer" +] @type + +[ + "allocatable" + "attributes" + "device" + "dimension" + "global" + "grid_global" + "host" + "optional" + "private" + "public" + "value" +] @type.qualifier + +[ + "endtype" + "type" +] @type.definition + +[ + "in" + "inout" + "out" +] @storageclass + +[ + "contains" + "import" +] @include + +[ + (none) + "implicit" + "intent" +] @attribute + +[ + "endfunction" + "endprogram" + "endsubroutine" + "function" + "procedure" + "subroutine" +] @keyword.function + +[ + "bind" + "call" + "class" + "continue" + "cycle" + "endenum" + "endinterface" + "endmodule" + "endprogram" + "enum" + "enumerator" + "equivalence" + "exit" + "format" + "goto" + "include" + "interface" + "module" + "namelist" + "only" + "parameter" + "print" + "program" + "read" + "stop" + "use" + "write" + (default) + (procedure_qualifier) +] @keyword + +"return" @keyword.return + +[ + "else" + "elseif" + "endif" + "endwhere" + "if" + "then" + "where" +] @conditional + +[ + "do" + "enddo" + "forall" + "while" +] @repeat + +[ + "*" + "+" + "-" + "/" + "=" + "<" + ">" + "<=" + ">=" + "==" + "/=" +] @operator + +[ + "\\.and\\." + "\\.or\\." + "\\.lt\\." + "\\.gt\\." + "\\.ge\\." + "\\.le\\." + "\\.eq\\." + "\\.eqv\\." + "\\.neqv\\." +] @keyword.operator + + ;; Brackets + [ + "(" + ")" + "[" + "]" + "<<<" + ">>>" + ] @punctuation.bracket + + ;; Delimiter + [ + "::" + "," + "%" + ] @punctuation.delimiter + +(parameters + (identifier) @parameter) + +(program_statement + (name) @namespace) + +(module_statement + (name) @namespace) + +(function_statement + (name) @function) + +(subroutine_statement + (name) @function) + +(end_program_statement + (name) @namespace) + +(end_module_statement + (name) @namespace) + +(end_function_statement + (name) @function) + +(end_subroutine_statement + (name) @function) + +(subroutine_call + (name) @function) + +(keyword_argument + name: (identifier) @keyword) + +(derived_type_member_expression + (type_member) @property) diff --git a/runtime/queries/fortran/indents.scm b/queries/fortran/indents.scm similarity index 90% rename from runtime/queries/fortran/indents.scm rename to queries/fortran/indents.scm index 0f9ba3d7e..67fa046de 100644 --- a/runtime/queries/fortran/indents.scm +++ b/queries/fortran/indents.scm @@ -5,11 +5,11 @@ (function) ; (interface) (if_statement) - (do_loop) + (do_loop_statement) (where_statement) (derived_type_definition) (enum) -] @indent.begin +] @indent [ (end_module_statement) @@ -24,4 +24,4 @@ (end_type_statement) (end_enum_statement) (end_where_statement) -] @indent.branch +] @branch diff --git a/runtime/queries/hcl/folds.scm b/queries/fusion/folds.scm similarity index 50% rename from runtime/queries/hcl/folds.scm rename to queries/fusion/folds.scm index e0c5313a2..179fc160b 100644 --- a/runtime/queries/hcl/folds.scm +++ b/queries/fusion/folds.scm @@ -1,6 +1,6 @@ [ (comment) (block) - (heredoc_template) - (object) + (afx_comment) + (afx_element) ] @fold diff --git a/queries/fusion/highlights.scm b/queries/fusion/highlights.scm new file mode 100644 index 000000000..b093f8872 --- /dev/null +++ b/queries/fusion/highlights.scm @@ -0,0 +1,120 @@ +(comment) @comment +(afx_comment) @comment + +; identifiers afx +(afx_opening_element + (afx_identifier) @tag) +(afx_closing_element + (afx_identifier) @tag) +(afx_element_self_closing + (afx_identifier) @tag) + +(afx_attribute + (afx_property_identifier) @tag.attribute) + +(afx_text) @text + +; identifiers eel + +(eel_object_path + (eel_path_identifier) @variable.builtin + (#match? @variable.builtin "^(this|props)$") +) + +(eel_object_path + (eel_path_identifier) @variable) + +(eel_object_pair + key: (eel_property_name) @property) + +(eel_method_name) @function + +(eel_parameter) @variable + +; identifiers fusion +; ----------- + +(path_part) @property +(meta_property) @attribute +(prototype_signature + "prototype" @keyword + +) +(include_statement + [ + "include" + ] @include + (source_file) @text.uri +) + +(namespace_declaration + "namespace" @keyword + (alias_namespace) @namespace) + +(type + name: (type_name) @type) + +; tokens +; ------ +(afx_opening_element + [ + "<" + ">" + ] @punctuation.bracket) + + (afx_closing_element + [ + "<" + ">" + "/" + ] @punctuation.bracket) + +(afx_element_self_closing + [ + "<" + "/>" + ] @punctuation.bracket) + +[ + (package_name) + (alias_namespace) +] @namespace + +(namespace_declaration "=" @operator) +(assignment "=" @operator) +(copy "<" @operator) +(deletion) @operator +(eel_binary_expression + operator: _ @operator) +(eel_not_expression + [ + "!" + "not" + ] @operator) + +(string) @string +(number) @number +(boolean) @boolean +(null) @constant.builtin + +(value_expression + start: _ @punctuation.special + end: _ @punctuation.special +) +[ + "(" + ")" + "{" + "}" + "[" + "]" +] @punctuation.bracket + +[ + ":" + "." + "?" +] @punctuation.delimiter + +(eel_ternary_expression + ["?" ":"] @conditional.ternary) diff --git a/queries/fusion/indents.scm b/queries/fusion/indents.scm new file mode 100644 index 000000000..68c57d528 --- /dev/null +++ b/queries/fusion/indents.scm @@ -0,0 +1,19 @@ +[ + (block) + (value_dsl) + (afx_element) + (afx_element_self_closing) + (eel_array) + (eel_object) +] @indent + + +(block end: _ @branch) +(value_dsl end: _ @branch) +(eel_array end: _ @branch) +(eel_object end: _ @branch) +[ + (afx_closing_element) +] @branch + +(comment) @ignore diff --git a/queries/fusion/locals.scm b/queries/fusion/locals.scm new file mode 100644 index 000000000..24dc57bbe --- /dev/null +++ b/queries/fusion/locals.scm @@ -0,0 +1,21 @@ +;; Fusion base +(block) @scope + +(namespace_declaration + (alias_namespace) @definition.namespace) + +(property + (path (path_part) @definition.field)) + +(type + namespace: (package_name)? @definition.namespace + name: (type_name) @definition.type +) + +;; Eel Expressions +(eel_arrow_function) @scope +(eel_object) @scope + +(eel_parameter) @definition.parameter +(eel_object_pair + key: (eel_property_name) @definition.field) diff --git a/queries/gdscript/highlights.scm b/queries/gdscript/highlights.scm new file mode 100644 index 000000000..7b5469f62 --- /dev/null +++ b/queries/gdscript/highlights.scm @@ -0,0 +1,126 @@ +;; Basic +(identifier) @variable +(name) @variable +(type) @type +(comment) @comment +(get_node) @string +(string) @string +(float) @float +(integer) @number +(null) @constant +(setter) @function +(getter) @function +(static_keyword) @type.qualifier +(tool_statement) @keyword +(breakpoint_statement) @keyword +(inferred_type) @operator +[(true) (false)] @boolean + +(class_name_statement + (name) @type) @keyword + +(const_statement + "const" @type.qualifier + (name) @constant) + +((identifier) @variable.builtin + (#eq? @variable.builtin "self")) + +;; Identifier naming conventions +((identifier) @type + (#lua-match? @type "^[A-Z]")) +((identifier) @constant + (#lua-match? @constant "^[A-Z][A-Z_0-9]*$")) +((identifier) @type + (#lua-match? @type "^[A-Z][A-Z_0-9]*$") . (_)) + +;; Functions +(constructor_definition) @constructor + +(function_definition + (name) @function (parameters + (identifier) @parameter)*) + +(typed_parameter + (identifier) @parameter) + +(default_parameter + (identifier) @parameter) + +(call + (identifier) @function) +(attribute_call + (identifier) @function) + +;; Alternations +["(" ")" "[" "]" "{" "}"] @punctuation.bracket + +["," "." ":"] @punctuation.delimiter + +["if" "elif" "else" "match"] @conditional + +["for" "while" "break" "continue"] @repeat + +[ + "~" + "-" + "*" + "/" + "%" + "+" + "-" + "<<" + ">>" + "&" + "^" + "|" + "<" + ">" + "==" + "!=" + ">=" + "<=" + "!" + "&&" + "||" + "=" + "+=" + "-=" + "*=" + "/=" + "%=" + "&=" + "|=" + "->" +] @operator + +[ + "and" + "as" + "in" + "is" + "not" + "or" +] @keyword.operator + +[ + "pass" + "class" + "class_name" + "extends" + "signal" + "func" + "enum" + "var" + "onready" + "export" + "setget" + "remote" + "master" + "puppet" + "remotesync" + "mastersync" + "puppetsync" +] @keyword + +"return" @keyword.return diff --git a/queries/gdscript/indents.scm b/queries/gdscript/indents.scm new file mode 100644 index 000000000..80b78234d --- /dev/null +++ b/queries/gdscript/indents.scm @@ -0,0 +1,24 @@ +[ + (if_statement) + + (for_statement) + (while_statement) + + (parenthesized_expression) + + (function_definition) + (class_definition) +] @indent + +((argument_list) @aligned_indent + (#set! "delimiter" "()")) +((parameters) @aligned_indent + (#set! "delimiter" "()")) + +[ + ")" + "]" + "}" + (elif_clause) + (else_clause) +] @branch diff --git a/queries/gdscript/injections.scm b/queries/gdscript/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/gdscript/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/queries/gdscript/locals.scm b/queries/gdscript/locals.scm new file mode 100644 index 000000000..313af2aef --- /dev/null +++ b/queries/gdscript/locals.scm @@ -0,0 +1,10 @@ +(function_definition) @definition.function + +[ + (extends_statement) + (variable_statement) + (expression_statement) + (if_statement) + (function_definition) + (body) +] @scope diff --git a/runtime/queries/git_rebase/highlights.scm b/queries/git_rebase/highlights.scm similarity index 74% rename from runtime/queries/git_rebase/highlights.scm rename to queries/git_rebase/highlights.scm index 248366e24..466bd2f16 100644 --- a/runtime/queries/git_rebase/highlights.scm +++ b/queries/git_rebase/highlights.scm @@ -1,7 +1,8 @@ ((command) @keyword (label)? @constant - (message)? @none @spell) + (message)? @text @spell) (option) @operator (comment) @comment + diff --git a/queries/git_rebase/injections.scm b/queries/git_rebase/injections.scm new file mode 100644 index 000000000..27388618e --- /dev/null +++ b/queries/git_rebase/injections.scm @@ -0,0 +1,5 @@ +((operation + (command) @_command + (message) @bash) +(#any-of? @_command "exec" "x")) + diff --git a/runtime/queries/gitattributes/highlights.scm b/queries/gitattributes/highlights.scm similarity index 62% rename from runtime/queries/gitattributes/highlights.scm rename to queries/gitattributes/highlights.scm index aec7750f6..73ec71438 100644 --- a/runtime/queries/gitattributes/highlights.scm +++ b/queries/gitattributes/highlights.scm @@ -1,15 +1,12 @@ (dir_sep) @punctuation.delimiter (quoted_pattern - "\"" @punctuation.special) + ("\"" @punctuation.special)) (range_notation) @string.special (range_notation - [ - "[" - "]" - ] @punctuation.bracket) + [ "[" "]" ] @punctuation.bracket) (wildcard) @character.special @@ -17,8 +14,7 @@ (character_class) @constant -(class_range - "-" @operator) +(class_range ("-" @operator)) [ (ansi_c_escape) @@ -26,7 +22,7 @@ ] @string.escape (attribute - (attr_name) @variable.parameter) + (attr_name) @parameter) (attribute (builtin_attr) @variable.builtin) @@ -41,15 +37,17 @@ (string_value) @string -(macro_tag) @keyword.directive +(macro_tag) @preproc (macro_def macro_name: (_) @property) -; we do not lint syntax errors -; [ -; (pattern_negation) -; (redundant_escape) -; (trailing_slash) -; ] @error +[ + (pattern_negation) + (redundant_escape) + (trailing_slash) +] @error + +(ERROR) @error + (comment) @comment @spell diff --git a/queries/gitattributes/injections.scm b/queries/gitattributes/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/gitattributes/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/queries/gitcommit/highlights.scm b/queries/gitcommit/highlights.scm new file mode 100644 index 000000000..ff0c4ddb3 --- /dev/null +++ b/queries/gitcommit/highlights.scm @@ -0,0 +1,33 @@ +(comment) @comment +(generated_comment) @comment +(title) @text.title +(text) @text +(branch) @text.reference +(change) @keyword +(filepath) @text.uri +(arrow) @punctuation.delimiter + +(subject) @text.title @spell +(subject (overflow) @text @spell) +(prefix (type) @keyword @nospell) +(prefix (scope) @parameter @nospell) +(prefix [ + "(" + ")" + ":" +] @punctuation.delimiter) +(prefix [ + "!" +] @punctuation.special) + +(message) @text @spell + +(trailer (token) @label) +(trailer (value) @text) + +(breaking_change (token) @text.warning) +(breaking_change (value) @text @spell) + +(scissor) @comment + +(ERROR) @error diff --git a/queries/gitcommit/injections.scm b/queries/gitcommit/injections.scm new file mode 100644 index 000000000..eecdeee47 --- /dev/null +++ b/queries/gitcommit/injections.scm @@ -0,0 +1,2 @@ +((diff) @diff (#exclude_children! @diff)) +(rebase_command) @git_rebase diff --git a/runtime/queries/gitignore/highlights.scm b/queries/gitignore/highlights.scm similarity index 76% rename from runtime/queries/gitignore/highlights.scm rename to queries/gitignore/highlights.scm index aafbe541e..6e83ea6f2 100644 --- a/runtime/queries/gitignore/highlights.scm +++ b/queries/gitignore/highlights.scm @@ -1,7 +1,5 @@ (comment) @comment @spell -(pattern_char) @string.special.path - [ (directory_separator) (directory_separator_escaped) @@ -11,26 +9,23 @@ (wildcard_char_single) (wildcard_chars) (wildcard_chars_allow_slash) -] @character.special + (bracket_negation) +] @operator + +(negation) @punctuation.special [ (pattern_char_escaped) (bracket_char_escaped) ] @string.escape -(negation) @punctuation.special - -(bracket_negation) @operator - -; bracket expressions +;; bracket expressions [ "[" "]" ] @punctuation.bracket (bracket_char) @constant - -(bracket_range +(bracket_range "-" @operator) - (bracket_char_class) @constant.builtin diff --git a/queries/gleam/folds.scm b/queries/gleam/folds.scm new file mode 100644 index 000000000..ff05eeb05 --- /dev/null +++ b/queries/gleam/folds.scm @@ -0,0 +1,11 @@ +; Folds +[ + (case) + (expression_group) + (function) + (public_function) + (anonymous_function) + (type_definition) + (public_type_definition) + (public_opaque_type_definition) +] @fold diff --git a/queries/gleam/highlights.scm b/queries/gleam/highlights.scm new file mode 100644 index 000000000..0e2712879 --- /dev/null +++ b/queries/gleam/highlights.scm @@ -0,0 +1,167 @@ +; Keywords +[ + "as" + "let" + "todo" + "try" +] @keyword + +; Function Keywords +[ + "fn" + "type" +] @keyword.function + +; Imports +[ + "import" +] @include + +; Conditionals +[ + "case" + "if" +] @conditional + +; Exceptions +[ + "assert" +] @exception + +; Punctuation +[ + "(" + ")" + "<<" + ">>" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +[ + "," + "." +] @punctuation.delimiter + +[ + "#" +] @punctuation.special + +; Operators +[ + "%" + "&&" + "*" + "*." + "+" + "+." + "-" + "-." + "->" + ".." + "/" + "/." + ":" + "<" + "<." + "<=" + "<=." + "=" + "==" + ">" + ">." + ">=" + ">=." + "|>" + "||" +] @operator + +; Identifiers +(identifier) @variable + +; Comments +[ + (module_comment) + (statement_comment) + (comment) +] @comment + +; Unused Identifiers +[ + (discard) + (hole) +] @comment + +; Modules & Imports +(module ("/" @namespace)?) @namespace +(import alias: ((identifier) @namespace)?) +(remote_type_identifier module: (identifier) @namespace) +(unqualified_import name: (identifier) @function) + +; Strings +(string) @string + +; Bit Strings +(bit_string_segment) @string.special + +; Numbers +[ + (integer) + (float) + (bit_string_segment_option_unit) +] @number + +; Function Parameter Labels +(function_call arguments: (arguments (argument label: (label) @symbol ":" @symbol))) +(function_parameter label: (label)? @symbol name: (identifier) @parameter (":" @parameter)?) + +; Records +(record arguments: (arguments (argument label: (label) @property ":" @property)?)) +(record_pattern_argument label: (label) @property ":" @property) +(record_update_argument label: (label) @property ":" @property) +(field_access record: (identifier) @variable field: (label) @property) + +; Type Constructors +(data_constructor_argument label: (label) @property ":" @property) + +; Type Parameters +(type_parameter) @parameter + +; Types +((type_identifier) @type (#not-any-of? @type "True" "False")) + +; Booleans +((type_identifier) @boolean (#any-of? @boolean "True" "False")) + +; Type Variables +(type_var) @type + +; Type Qualifiers +[ + "const" + "external" + "opaque" + "pub" +] @type.qualifier + +; Tuples +(tuple_access index: (integer) @operator) + +; Functions +(function name: (identifier) @function) +(public_function name: (identifier) @function) +(function_call function: (identifier) @function) +(function_call function: (field_access field: (label) @function)) + +; External Functions +(public_external_function name: (identifier) @function) +(external_function name: (identifier) @function) +(external_function_body (string) @namespace . (string) @function) + +; Pipe Operator +(binary_expression operator: "|>" right: (identifier) @function) + +; Parser Errors +(ERROR) @error diff --git a/queries/gleam/indents.scm b/queries/gleam/indents.scm new file mode 100644 index 000000000..e2259b688 --- /dev/null +++ b/queries/gleam/indents.scm @@ -0,0 +1,33 @@ +; Gleam indents similar to Rust and JavaScript +[ + (assert) + (case) + (case_clause) + (constant) + (expression_group) + (external_function) + (function) + (import) + (let) + (list) + (public_constant) + (public_external_function) + (public_function) + (public_opaque_type_definition) + (public_type_alias) + (public_type_definition) + (todo) + (try) + (tuple) + (type_alias) + (type_definition) +] @indent + +[ + ")" + "]" + "}" +] @indent_end @branch + +; Gleam pipelines are not indented, but other binary expression chains are +((binary_expression operator: _ @_operator) @indent (#not-eq? @_operator "|>")) diff --git a/queries/gleam/injections.scm b/queries/gleam/injections.scm new file mode 100644 index 000000000..ed4c2de91 --- /dev/null +++ b/queries/gleam/injections.scm @@ -0,0 +1,6 @@ +; Comments +[ + (module_comment) + (statement_comment) + (comment) +] @comment diff --git a/queries/gleam/locals.scm b/queries/gleam/locals.scm new file mode 100644 index 000000000..8872e51f0 --- /dev/null +++ b/queries/gleam/locals.scm @@ -0,0 +1,24 @@ +; Let Binding Definition +(let pattern: (identifier) @definition) + +; List Pattern Definitions +(list_pattern (identifier) @definition) +(list_pattern assign: (identifier) @definition) + +; Tuple Pattern Definition +(tuple_pattern (identifier) @definition) + +; Record Pattern Definition +(record_pattern_argument pattern: (identifier) @definition) + +; Function Parameter Definition +(function_parameter name: (identifier) @definition) + +; References +(identifier) @reference + +; Function Body Scope +(function_body) @scope + +; Case Scope +(case_clause) @scope diff --git a/queries/glimmer/highlights.scm b/queries/glimmer/highlights.scm new file mode 100644 index 000000000..b1b3f9141 --- /dev/null +++ b/queries/glimmer/highlights.scm @@ -0,0 +1,88 @@ +; === Tag Names === + +; Tags that start with a lower case letter are HTML tags +; We'll also use this highlighting for named blocks (which start with `:`) +((tag_name) @tag + (#match? @tag "^(:)?[a-z]")) +; Tags that start with a capital letter are Glimmer components +((tag_name) @constructor + (#lua-match? @constructor "^[A-Z]")) + +(attribute_name) @property + +(string_literal) @string +(number_literal) @number +(boolean_literal) @boolean + +(concat_statement) @string + +; === Block Statements === + +; Highlight the brackets +(block_statement_start) @tag.delimiter +(block_statement_end) @tag.delimiter + +; Highlight `if`/`each`/`let` +(block_statement_start path: (identifier) @conditional) +(block_statement_end path: (identifier) @conditional) +((mustache_statement (identifier) @conditional) + (#lua-match? @conditional "else")) + +; == Mustache Statements === + +; Highlight the whole statement, to color brackets and separators +(mustache_statement) @tag.delimiter + +; An identifier in a mustache expression is a variable +((mustache_statement [ + (path_expression (identifier) @variable) + (identifier) @variable + ]) + (#not-match? @variable "yield|outlet|this|else")) +; As are arguments in a block statement +(block_statement_start argument: [ + (path_expression (identifier) @variable) + (identifier) @variable + ]) +; As is an identifier in a block param +(block_params (identifier) @variable) +; As are helper arguments +((helper_invocation argument: [ + (path_expression (identifier) @variable) + (identifier) @variable + ]) + (#not-match? @variable "this")) +; `this` should be highlighted as a built-in variable +((identifier) @variable.builtin + (#lua-match? @variable.builtin "this")) + +; If the identifier is just "yield" or "outlet", it's a keyword +((mustache_statement (identifier) @keyword) + (#any-of? @keyword "yield" "outlet")) + +; Helpers are functions +((helper_invocation helper: [ + (path_expression (identifier) @function) + (identifier) @function + ]) + (#not-match? @function "if|yield")) +((helper_invocation helper: (identifier) @conditional) + (#lua-match? @conditional "if")) +((helper_invocation helper: (identifier) @keyword) + (#lua-match? @keyword "yield")) + +(hash_pair key: (identifier) @property) + +(comment_statement) @comment + +(attribute_node "=" @operator) + +(block_params "as" @keyword) +(block_params "|" @operator) + +[ + "<" + ">" + "" +] @tag.delimiter diff --git a/runtime/queries/glsl/folds.scm b/queries/glsl/folds.scm similarity index 100% rename from runtime/queries/glsl/folds.scm rename to queries/glsl/folds.scm diff --git a/runtime/queries/glsl/highlights.scm b/queries/glsl/highlights.scm similarity index 70% rename from runtime/queries/glsl/highlights.scm rename to queries/glsl/highlights.scm index d4583f0ea..4e5e57f47 100644 --- a/runtime/queries/glsl/highlights.scm +++ b/queries/glsl/highlights.scm @@ -25,11 +25,13 @@ "noperspective" "invariant" "precise" -] @keyword.modifier +] @type.qualifier "subroutine" @keyword.function -(extension_storage_class) @keyword.modifier +(extension_storage_class) @storageclass -((identifier) @variable.builtin - (#lua-match? @variable.builtin "^gl_")) +( + (identifier) @variable.builtin + (#match? @variable.builtin "^gl_") +) diff --git a/runtime/queries/glsl/indents.scm b/queries/glsl/indents.scm similarity index 100% rename from runtime/queries/glsl/indents.scm rename to queries/glsl/indents.scm diff --git a/queries/glsl/injections.scm b/queries/glsl/injections.scm new file mode 100644 index 000000000..7d3323b16 --- /dev/null +++ b/queries/glsl/injections.scm @@ -0,0 +1,3 @@ +(preproc_arg) @glsl + +(comment) @comment diff --git a/runtime/queries/glsl/locals.scm b/queries/glsl/locals.scm similarity index 100% rename from runtime/queries/glsl/locals.scm rename to queries/glsl/locals.scm diff --git a/queries/go/folds.scm b/queries/go/folds.scm new file mode 100644 index 000000000..e1b7a83e9 --- /dev/null +++ b/queries/go/folds.scm @@ -0,0 +1,16 @@ +[ + (const_declaration) + (expression_switch_statement) + (for_statement) + (func_literal) + (function_declaration) + (if_statement) + (import_declaration) + (method_declaration) + (type_declaration) + (var_declaration) + (composite_literal) + (literal_element) + (block) +] @fold + diff --git a/queries/go/highlights.scm b/queries/go/highlights.scm new file mode 100644 index 000000000..be72804b6 --- /dev/null +++ b/queries/go/highlights.scm @@ -0,0 +1,215 @@ +;; Forked from tree-sitter-go +;; Copyright (c) 2014 Max Brunsfeld (The MIT License) + +;; +; Identifiers + +(type_identifier) @type +(type_spec name: (type_identifier) @type.definition) +(field_identifier) @property +(identifier) @variable +(package_identifier) @namespace + +(parameter_declaration (identifier) @parameter) +(variadic_parameter_declaration (identifier) @parameter) + +(label_name) @label + +((identifier) @constant + (#eq? @constant "_")) + +(const_spec + name: (identifier) @constant) + +; Function calls + +(call_expression + function: (identifier) @function.call) + +(call_expression + function: (selector_expression + field: (field_identifier) @method.call)) + +; Function definitions + +(function_declaration + name: (identifier) @function) + +(method_declaration + name: (field_identifier) @method) + +(method_spec + name: (field_identifier) @method) + +; Operators + +[ + "--" + "-" + "-=" + ":=" + "!" + "!=" + "..." + "*" + "*" + "*=" + "/" + "/=" + "&" + "&&" + "&=" + "%" + "%=" + "^" + "^=" + "+" + "++" + "+=" + "<-" + "<" + "<<" + "<<=" + "<=" + "=" + "==" + ">" + ">=" + ">>" + ">>=" + "|" + "|=" + "||" + "~" +] @operator + +; Keywords + +[ + "break" + "chan" + "const" + "continue" + "default" + "defer" + "go" + "goto" + "interface" + "map" + "range" + "select" + "struct" + "type" + "var" + "fallthrough" +] @keyword + +"func" @keyword.function +"return" @keyword.return + +"for" @repeat + +[ + "import" + "package" +] @include + +[ + "else" + "case" + "switch" + "if" + ] @conditional + + +;; Builtin types + +((type_identifier) @type.builtin + (#any-of? @type.builtin + "any" + "bool" + "byte" + "complex128" + "complex64" + "error" + "float32" + "float64" + "int" + "int16" + "int32" + "int64" + "int8" + "rune" + "string" + "uint" + "uint16" + "uint32" + "uint64" + "uint8" + "uintptr")) + + +;; Builtin functions + +((identifier) @function.builtin + (#any-of? @function.builtin + "append" + "cap" + "close" + "complex" + "copy" + "delete" + "imag" + "len" + "make" + "new" + "panic" + "print" + "println" + "real" + "recover")) + + +; Delimiters + +"." @punctuation.delimiter +"," @punctuation.delimiter +":" @punctuation.delimiter +";" @punctuation.delimiter + +"(" @punctuation.bracket +")" @punctuation.bracket +"{" @punctuation.bracket +"}" @punctuation.bracket +"[" @punctuation.bracket +"]" @punctuation.bracket + + +; Literals + +(interpreted_string_literal) @string +(raw_string_literal) @string @spell +(rune_literal) @string +(escape_sequence) @string.escape + +(int_literal) @number +(float_literal) @float +(imaginary_literal) @number + +(true) @boolean +(false) @boolean +(nil) @constant.builtin + +(keyed_element + . (literal_element (identifier) @field)) +(field_declaration name: (field_identifier) @field) + +(comment) @comment @spell + +(ERROR) @error + +((interpreted_string_literal) @spell + (#not-has-parent? @spell + import_spec + ) +) diff --git a/queries/go/indents.scm b/queries/go/indents.scm new file mode 100644 index 000000000..c6ac18969 --- /dev/null +++ b/queries/go/indents.scm @@ -0,0 +1,31 @@ +[ + (import_declaration) + (const_declaration) + (var_declaration) + (type_declaration) + (func_literal) + (literal_value) + (expression_case) + (default_case) + (block) + (call_expression) + (parameter_list) + (struct_type) +] @indent + +[ + "}" +] @branch + +(const_declaration ")" @branch) +(import_spec_list ")" @branch) +(var_declaration ")" @branch) + +[ + "}" + ")" +] @indent_end + +(parameter_list ")" @branch) + +(comment) @ignore diff --git a/queries/go/injections.scm b/queries/go/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/go/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/queries/go/locals.scm b/queries/go/locals.scm new file mode 100644 index 000000000..1de546c7c --- /dev/null +++ b/queries/go/locals.scm @@ -0,0 +1,79 @@ +( + (function_declaration + name: (identifier) @definition.function) ;@function +) + +( + (method_declaration + name: (field_identifier) @definition.method); @method +) + +(short_var_declaration + left: (expression_list + (identifier) @definition.var)) + +(var_spec + name: (identifier) @definition.var) + +(parameter_declaration (identifier) @definition.var) +(variadic_parameter_declaration (identifier) @definition.var) + +(for_statement + (range_clause + left: (expression_list + (identifier) @definition.var))) + +(const_declaration + (const_spec + name: (identifier) @definition.var)) + +(type_declaration + (type_spec + name: (type_identifier) @definition.type)) + +;; reference +(identifier) @reference +(type_identifier) @reference +(field_identifier) @reference +((package_identifier) @reference + (set! reference.kind "namespace")) + +(package_clause + (package_identifier) @definition.namespace) + +(import_spec_list + (import_spec + name: (package_identifier) @definition.namespace)) + +;; Call references +((call_expression + function: (identifier) @reference) + (set! reference.kind "call" )) + +((call_expression + function: (selector_expression + field: (field_identifier) @reference)) + (set! reference.kind "call" )) + + +((call_expression + function: (parenthesized_expression + (identifier) @reference)) + (set! reference.kind "call" )) + +((call_expression + function: (parenthesized_expression + (selector_expression + field: (field_identifier) @reference))) + (set! reference.kind "call" )) + +;; Scopes + +(func_literal) @scope +(source_file) @scope +(function_declaration) @scope +(if_statement) @scope +(block) @scope +(expression_switch_statement) @scope +(for_statement) @scope +(method_declaration) @scope diff --git a/runtime/queries/beancount/folds.scm b/queries/godot_resource/folds.scm similarity index 57% rename from runtime/queries/beancount/folds.scm rename to queries/godot_resource/folds.scm index 9f1b6cbed..943e0628f 100644 --- a/runtime/queries/beancount/folds.scm +++ b/queries/godot_resource/folds.scm @@ -1,4 +1,3 @@ [ - (transaction) (section) ] @fold diff --git a/queries/godot_resource/highlights.scm b/queries/godot_resource/highlights.scm new file mode 100644 index 000000000..005ddaacb --- /dev/null +++ b/queries/godot_resource/highlights.scm @@ -0,0 +1,28 @@ +(identifier) @type.builtin + +(attribute (identifier) @property) +(property (path) @property) +(constructor (identifier) @constructor) + +(string) @string +(integer) @number +(float) @float + +(true) @constant.builtin +(false) @constant.builtin + +[ + "[" + "]" +] @tag.delimiter + +[ + "(" + ")" + "{" + "}" +] @punctuation.bracket + +"=" @operator + +(ERROR) @error diff --git a/queries/godot_resource/locals.scm b/queries/godot_resource/locals.scm new file mode 100644 index 000000000..1dce04f0c --- /dev/null +++ b/queries/godot_resource/locals.scm @@ -0,0 +1,3 @@ +[ + (section) +] @scope diff --git a/queries/gomod/highlights.scm b/queries/gomod/highlights.scm new file mode 100644 index 000000000..63e1f0128 --- /dev/null +++ b/queries/gomod/highlights.scm @@ -0,0 +1,17 @@ +[ + "require" + "replace" + "go" + "exclude" + "retract" + "module" +] @keyword + +"=>" @operator + +(comment) @comment + +[ +(version) +(go_version) +] @string diff --git a/queries/gomod/injections.scm b/queries/gomod/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/gomod/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/runtime/queries/gowork/highlights.scm b/queries/gowork/highlights.scm similarity index 56% rename from runtime/queries/gowork/highlights.scm rename to queries/gowork/highlights.scm index bca9a5f80..9c84bcc44 100644 --- a/runtime/queries/gowork/highlights.scm +++ b/queries/gowork/highlights.scm @@ -6,9 +6,9 @@ "=>" @operator -(comment) @comment @spell +(comment) @comment [ - (version) - (go_version) +(version) +(go_version) ] @string diff --git a/queries/gowork/injections.scm b/queries/gowork/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/gowork/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/runtime/queries/graphql/highlights.scm b/queries/graphql/highlights.scm similarity index 85% rename from runtime/queries/graphql/highlights.scm rename to queries/graphql/highlights.scm index c1ee501c4..3a9d47dad 100644 --- a/runtime/queries/graphql/highlights.scm +++ b/queries/graphql/highlights.scm @@ -1,5 +1,6 @@ ; Types ;------ + (scalar_type_definition (name) @type) @@ -41,6 +42,7 @@ ; Directives ;----------- + (directive_definition "@" @attribute (name) @attribute) @@ -49,6 +51,7 @@ ; Properties ;----------- + (field (name) @property) @@ -66,8 +69,9 @@ (enum_value (name) @property) -; Variable Definitions and Arguments +; Variable Definitions and Arguments ;----------------------------------- + (operation_definition (name) @variable) @@ -76,17 +80,17 @@ (input_fields_definition (input_value_definition - (name) @variable.parameter)) + (name) @parameter)) (argument - (name) @variable.parameter) + (name) @parameter) (arguments_definition (input_value_definition - (name) @variable.parameter)) + (name) @parameter)) (variable_definition - (variable) @variable.parameter) + (variable) @parameter) (argument (value @@ -94,20 +98,22 @@ ; Constants ;---------- + (string_value) @string (int_value) @number -(float_value) @number.float +(float_value) @float (boolean_value) @boolean ; Literals ;--------- -(description - (string_value) @string.documentation @spell) -(comment) @comment @spell +(description + (string_value) @comment) + +(comment) @comment (directive_location (executable_directive_location) @type.builtin) @@ -117,12 +123,17 @@ ; Keywords ;---------- + [ "query" "mutation" "subscription" "fragment" "scalar" + "type" + "interface" + "union" + "enum" "input" "extend" "directive" @@ -132,32 +143,23 @@ "implements" ] @keyword -[ - "enum" - "union" - "type" - "interface" -] @keyword.type - ; Punctuation ;------------ + [ - "(" - ")" - "[" - "]" - "{" - "}" + "(" + ")" + "[" + "]" + "{" + "}" ] @punctuation.bracket "=" @operator "|" @punctuation.delimiter - "&" @punctuation.delimiter - ":" @punctuation.delimiter "..." @punctuation.special - "!" @punctuation.special diff --git a/queries/graphql/indents.scm b/queries/graphql/indents.scm new file mode 100644 index 000000000..0f222b6d4 --- /dev/null +++ b/queries/graphql/indents.scm @@ -0,0 +1,9 @@ +[ + (definition) + (selection) +] @indent + +[ + "{" + "}" +] @branch diff --git a/queries/graphql/injections.scm b/queries/graphql/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/graphql/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/runtime/queries/hack/highlights.scm b/queries/hack/highlights.scm similarity index 55% rename from runtime/queries/hack/highlights.scm rename to queries/hack/highlights.scm index f74233e23..e79d62c75 100644 --- a/runtime/queries/hack/highlights.scm +++ b/queries/hack/highlights.scm @@ -1,54 +1,43 @@ (variable) @variable - (identifier) @variable - ((variable) @variable.builtin - (#eq? @variable.builtin "$this")) + (#eq? @variable.builtin "$this")) (braced_expression) @none (scoped_identifier - (qualified_identifier - (identifier) @type)) + (qualified_identifier + (identifier) @type)) [ (comment) (heredoc) -] @comment @spell - -((comment) @comment.documentation - (#lua-match? @comment.documentation "^/[*][*][^*].*[*]/$")) +] @comment "function" @keyword.function [ - "implements" - "using" - "attribute" - "const" - "extends" - "insteadof" + "async" + "await" + "type" + "interface" + "implements" + "class" + "using" + "namespace" + "attribute" + "const" + "extends" + "insteadof" ] @keyword [ - "class" - "type" - "interface" - "namespace" -] @keyword.type - -[ - "async" - "await" -] @keyword.coroutine - -[ - "use" - "include" - "include_once" - "require" - "require_once" -] @keyword.import + "use" + "include" + "include_once" + "require" + "require_once" +] @include [ "new" @@ -67,7 +56,7 @@ (static_modifier) (visibility_modifier) (xhp_modifier) -] @keyword.modifier +] @type.qualifier [ "shape" @@ -85,7 +74,9 @@ "noreturn" ] @type.builtin -(null) @constant.builtin +[ + (null) +] @constant.builtin [ (true) @@ -93,23 +84,14 @@ ] @boolean (type_specifier) @type - (new_expression (_) @type) -(alias_declaration - "newtype" - . - (_) @type) - -(alias_declaration - "type" - . - (_) @type) +(alias_declaration "newtype" . (_) @type) +(alias_declaration "type" . (_) @type) (class_declaration name: (identifier) @type) - (type_parameter name: (identifier) @type) @@ -118,8 +100,8 @@ (identifier) @type .)) [ - "@required" - "@lateinit" + "@required" + "@lateinit" (attribute_modifier) ] @attribute @@ -138,6 +120,7 @@ "/=" "%=" "**=" + "==>" "|>" "??" @@ -165,158 +148,132 @@ "/" "%" "**" + "++" "--" "!" + "?:" + + "=" + "??=" + ".=" + "|=" + "^=" + "&=" + "<<=" + ">>=" + "+=" + "-=" + "*=" + "/=" + "%=" + "**=" "=>" - ; type modifiers + + ;; type modifiers "@" "?" "~" ] @operator (integer) @number - -(float) @number.float +(float) @float (parameter - (variable) @variable.parameter) + (variable) @parameter) (call_expression - function: (qualified_identifier - (identifier) @function.call .)) + function: (qualified_identifier (identifier) @function.call .)) (call_expression - function: (scoped_identifier - (identifier) @function.call .)) + function: (scoped_identifier (identifier) @function.call .)) (call_expression function: (selection_expression - (qualified_identifier - (identifier) @function.method.call .))) + (qualified_identifier (identifier) @method.call .))) (qualified_identifier - (_) @module - . + (_) @namespace . (_)) (use_statement (qualified_identifier - (_) @module .) + (_) @namespace .) (use_clause)) (use_statement - (use_type - "namespace") + (use_type "namespace") (use_clause (qualified_identifier - (identifier) @module .) - alias: (identifier)? @module)) + (identifier) @namespace .) + alias: (identifier)? @namespace)) (use_statement - (use_type - "const") + (use_type "const") (use_clause (qualified_identifier - (identifier) @constant .) + (identifier) @constant .) alias: (identifier)? @constant)) (use_statement - (use_type - "function") + (use_type "function") (use_clause (qualified_identifier - (identifier) @function .) + (identifier) @function .) alias: (identifier)? @function)) (use_statement - (use_type - "type") + (use_type "type") (use_clause (qualified_identifier - (identifier) @type .) + (identifier) @type .) alias: (identifier)? @type)) (use_clause - (use_type - "namespace") + (use_type "namespace") (qualified_identifier - (_) @module .) - alias: (identifier)? @module) + (_) @namespace .) + alias: (identifier)? @namespace) (use_clause - (use_type - "function") + (use_type "function") (qualified_identifier - (_) @function .) + (_) @function .) alias: (identifier)? @function) (use_clause - (use_type - "const") + (use_type "const") (qualified_identifier - (_) @constant .) + (_) @constant .) alias: (identifier)? @constant) (use_clause - (use_type - "type") + (use_type "type") (qualified_identifier - (_) @type .) + (_) @type .) alias: (identifier)? @type) (function_declaration name: (identifier) @function) - (method_declaration - name: (identifier) @function.method) + name: (identifier) @method) (type_arguments - [ - "<" - ">" - ] @punctuation.bracket) - -[ - "(" - ")" - "[" - "]" - "{" - "}" - "<<" - ">>" -] @punctuation.bracket + [ "<" ">" ] @punctuation.bracket) +[ "(" ")" "[" "]" "{" "}" "<<" ">>"] @punctuation.bracket (xhp_open - [ - "<" - ">" - ] @tag.delimiter) - + [ "<" ">" ] @tag.delimiter) (xhp_close - [ - "" - ] @tag.delimiter) - -[ - "." - ";" - "::" - ":" - "," -] @punctuation.delimiter + [ "" ] @tag.delimiter) +[ "." ";" "::" ":" "," ] @punctuation.delimiter (qualified_identifier "\\" @punctuation.delimiter) (ternary_expression - [ - "?" - ":" - ] @keyword.conditional.ternary) + ["?" ":"] @conditional.ternary) [ "if" @@ -324,13 +281,13 @@ "elseif" "switch" "case" -] @keyword.conditional +] @conditional [ "try" "catch" "finally" -] @keyword.exception +] @exception [ "for" @@ -339,14 +296,16 @@ "do" "continue" "break" -] @keyword.repeat +] @repeat [ - (string) - (xhp_string) + (string) + (xhp_string) ] @string [ - (xhp_open) - (xhp_close) + (xhp_open) + (xhp_close) ] @tag + +(ERROR) @error diff --git a/queries/haskell/folds.scm b/queries/haskell/folds.scm new file mode 100644 index 000000000..28eadf8f3 --- /dev/null +++ b/queries/haskell/folds.scm @@ -0,0 +1,5 @@ +[ + (exp_apply) + (exp_do) + (function) +] @fold diff --git a/queries/haskell/highlights.scm b/queries/haskell/highlights.scm new file mode 100644 index 000000000..fa342fb8e --- /dev/null +++ b/queries/haskell/highlights.scm @@ -0,0 +1,148 @@ +;; ---------------------------------------------------------------------------- +;; Literals and comments + +(integer) @number +(exp_negation) @number +(exp_literal (float)) @float +(char) @character +(string) @string + +(con_unit) @symbol ; unit, as in () + +(comment) @comment + + +;; ---------------------------------------------------------------------------- +;; Punctuation + +[ + "(" + ")" + "{" + "}" + "[" + "]" +] @punctuation.bracket + +[ + (comma) + ";" +] @punctuation.delimiter + + +;; ---------------------------------------------------------------------------- +;; Keywords, operators, includes + +[ + "forall" + "∀" +] @repeat + +(pragma) @preproc + +[ + "if" + "then" + "else" + "case" + "of" +] @conditional + +[ + "import" + "qualified" + "module" +] @include + +[ + (operator) + (constructor_operator) + (type_operator) + (tycon_arrow) + (qualified_module) ; grabs the `.` (dot), ex: import System.IO + (all_names) + (wildcard) + "=" + "|" + "::" + "=>" + "->" + "<-" + "\\" + "`" + "@" +] @operator + +(module) @namespace + +[ + (where) + "let" + "in" + "class" + "instance" + "pattern" + "data" + "newtype" + "family" + "type" + "as" + "hiding" + "deriving" + "via" + "stock" + "anyclass" + "do" + "mdo" + "rec" + "infix" + "infixl" + "infixr" +] @keyword + + +;; ---------------------------------------------------------------------------- +;; Functions and variables + +(variable) @variable +(pat_wildcard) @variable + +(signature name: (variable) @type) +(function + name: (variable) @function + patterns: (patterns)) +((signature (fun)) . (function (variable) @function)) +((signature (context (fun))) . (function (variable) @function)) +((signature (forall (context (fun)))) . (function (variable) @function)) + +(exp_infix (variable) @operator) ; consider infix functions as operators + +(exp_infix (exp_name) @function.call (#set! "priority" 101)) +(exp_apply . (exp_name (variable) @function.call)) +(exp_apply . (exp_name (qualified_variable (variable) @function.call))) + + +;; ---------------------------------------------------------------------------- +;; Types + +(type) @type +(type_variable) @type + +(constructor) @constructor + +; True or False +((constructor) @_bool (#match? @_bool "(True|False)")) @boolean + + +;; ---------------------------------------------------------------------------- +;; Quasi-quotes + +(quoter) @function.call +; Highlighting of quasiquote_body is handled by injections.scm + +;; ---------------------------------------------------------------------------- +;; Spell checking + +(string) @spell +(comment) @spell + diff --git a/queries/haskell/injections.scm b/queries/haskell/injections.scm new file mode 100644 index 000000000..206248f6e --- /dev/null +++ b/queries/haskell/injections.scm @@ -0,0 +1,78 @@ +;; ----------------------------------------------------------------------------- +;; General language injection + +(quasiquote + ((quoter) @language) + ((quasiquote_body) @content) +) + +(comment) @comment + +;; ----------------------------------------------------------------------------- +;; shakespeare library +;; NOTE: doesn't support templating + +; TODO: add once CoffeeScript parser is added +; ; CoffeeScript: Text.Coffee +; (quasiquote +; (quoter) @_name +; (#eq? @_name "coffee") +; ((quasiquote_body) @coffeescript) + +; CSS: Text.Cassius, Text.Lucius +(quasiquote + (quoter) @_name + (#any-of? @_name "cassius" "lucius") + ((quasiquote_body) @css) +) + +; HTML: Text.Hamlet +(quasiquote + (quoter) @_name + (#any-of? @_name "shamlet" "xshamlet" "hamlet" "xhamlet" "ihamlet") + ((quasiquote_body) @html) +) + +; JS: Text.Julius +(quasiquote + (quoter) @_name + (#any-of? @_name "js" "julius") + ((quasiquote_body) @javascript) +) + +; TS: Text.TypeScript +(quasiquote + (quoter) @_name + (#any-of? @_name "tsc" "tscJSX") + ((quasiquote_body) @typescript) +) + + +;; ----------------------------------------------------------------------------- +;; HSX + +(quasiquote + (quoter) @_name + (#eq? @_name "hsx") + ((quasiquote_body) @html) +) + +;; ----------------------------------------------------------------------------- +;; Inline JSON from aeson + +(quasiquote + (quoter) @_name + (#eq? @_name "aesonQQ") + ((quasiquote_body) @json) +) + + +;; ----------------------------------------------------------------------------- +;; SQL + +; postgresql-simple +(quasiquote + (quoter) @_name + (#eq? @_name "sql") + ((quasiquote_body) @sql) +) diff --git a/queries/hcl/folds.scm b/queries/hcl/folds.scm new file mode 100644 index 000000000..cb20b2aa8 --- /dev/null +++ b/queries/hcl/folds.scm @@ -0,0 +1,6 @@ +[ + (comment) + (block) + (heredoc_template) + (object) +] @fold diff --git a/runtime/queries/hcl/highlights.scm b/queries/hcl/highlights.scm similarity index 52% rename from runtime/queries/hcl/highlights.scm rename to queries/hcl/highlights.scm index f2c784f6f..658369292 100644 --- a/runtime/queries/hcl/highlights.scm +++ b/queries/hcl/highlights.scm @@ -1,10 +1,11 @@ ; highlights.scm + [ "!" - "*" + "\*" "/" "%" - "+" + "\+" "-" ">" ">=" @@ -34,7 +35,7 @@ [ (ellipsis) - "?" + "\?" "=>" ] @punctuation.special @@ -47,17 +48,17 @@ "for" "endfor" "in" -] @keyword.repeat +] @repeat -[ +[ "if" "else" "endif" -] @keyword.conditional +] @conditional [ (quoted_template_start) ; " - (quoted_template_end) ; " + (quoted_template_end); " (template_literal) ; non-interpolation/directive content ] @string @@ -75,44 +76,27 @@ ] @punctuation.special (numeric_lit) @number - (bool_lit) @boolean - (null_lit) @constant - (comment) @comment @spell - (identifier) @variable -(body - (block - (identifier) @keyword)) - -(body - (block - (body - (block - (identifier) @type)))) - -(function_call - (identifier) @function) - -(attribute - (identifier) @variable.member) +(block (identifier) @type) +(function_call (identifier) @function) +(attribute (identifier) @field) ; { key: val } ; ; highlight identifier keys as though they were block attributes -(object_elem - key: (expression - (variable_expr - (identifier) @variable.member))) +(object_elem key: (expression (variable_expr (identifier) @field))) -; var.foo, data.bar -; -; first element in get_attr is a variable.builtin or a reference to a variable.builtin -(expression +((identifier) @keyword (#any-of? @keyword "module" "root" "cwd" "resource" "variable" "data" "locals" "terraform" "provider" "output")) +((identifier) @type.builtin (#any-of? @type.builtin "bool" "string" "number" "object" "tuple" "list" "map" "set" "any")) +(variable_expr (identifier) @variable.builtin (#any-of? @variable.builtin "var" "local" "path")) +(get_attr (identifier) @variable.builtin (#any-of? @variable.builtin "root" "cwd" "module")) + +(object_elem val: (expression (variable_expr - (identifier) @variable.builtin) - (get_attr - (identifier) @variable.member)) + (identifier) @type.builtin (#any-of? @type.builtin "bool" "string" "number" "object" "tuple" "list" "map" "set" "any")))) + +(ERROR) @error diff --git a/queries/hcl/indents.scm b/queries/hcl/indents.scm new file mode 100644 index 000000000..d68ec3081 --- /dev/null +++ b/queries/hcl/indents.scm @@ -0,0 +1,15 @@ +[ + (block) + (object) + (tuple) + (function_call) +] @indent + +[ + "]" + ")" + "}" +] @branch @indent_end + +(comment) @auto +(ERROR) @auto diff --git a/queries/hcl/injections.scm b/queries/hcl/injections.scm new file mode 100644 index 000000000..94451beb4 --- /dev/null +++ b/queries/hcl/injections.scm @@ -0,0 +1,7 @@ +(comment) @comment + +(heredoc_template + (template_literal) @content + (heredoc_identifier) @language + (#set! "language" @language) + (#downcase! "language")) diff --git a/runtime/queries/heex/folds.scm b/queries/heex/folds.scm similarity index 100% rename from runtime/queries/heex/folds.scm rename to queries/heex/folds.scm diff --git a/runtime/queries/heex/highlights.scm b/queries/heex/highlights.scm similarity index 76% rename from runtime/queries/heex/highlights.scm rename to queries/heex/highlights.scm index e2fb01880..7dd4dd6fd 100644 --- a/runtime/queries/heex/highlights.scm +++ b/queries/heex/highlights.scm @@ -27,28 +27,30 @@ (doctype) @constant ; HEEx comments are highlighted as such -(comment) @comment @spell +(comment) @comment ; HEEx text content is treated as markup -; (text) @none +(text) @text + +; Tree-sitter parser errors +(ERROR) @error + ; HEEx tags and slots are highlighted as HTML [ - (tag_name) - (slot_name) + (tag_name) + (slot_name) ] @tag ; HEEx attributes are highlighted as HTML attributes (attribute_name) @tag.attribute - [ (attribute_value) (quoted_attribute_value) ] @string ; HEEx components are highlighted as modules and function calls -(component_name - [ - (module) @type - (function) @function - "." @punctuation.delimiter - ]) +(component_name [ + (module) @type + (function) @function + "." @punctuation.delimiter +]) diff --git a/runtime/queries/heex/indents.scm b/queries/heex/indents.scm similarity index 83% rename from runtime/queries/heex/indents.scm rename to queries/heex/indents.scm index 82a2f8912..99fc693dc 100644 --- a/runtime/queries/heex/indents.scm +++ b/queries/heex/indents.scm @@ -3,18 +3,18 @@ (component) (slot) (tag) -] @indent.begin +] @indent ; Dedent at the end of each tag, component, and slot [ (end_component) (end_slot) (end_tag) -] @indent.branch @indent.dedent +] @branch @dedent ; Self-closing tags and components should not change ; indentation level of sibling nodes [ (self_closing_component) (self_closing_tag) -] @indent.auto +] @auto diff --git a/queries/heex/injections.scm b/queries/heex/injections.scm new file mode 100644 index 000000000..fffd1dc53 --- /dev/null +++ b/queries/heex/injections.scm @@ -0,0 +1,11 @@ +; HEEx directives can span multiple interpolated lines of Elixir +(directive [ + (expression_value) + (partial_expression_value) +] @elixir @combined) + +; HEEx Elixir expressions are always within a tag or component +(expression (expression_value) @elixir) + +; HEEx comments +(comment) @comment diff --git a/runtime/queries/heex/locals.scm b/queries/heex/locals.scm similarity index 85% rename from runtime/queries/heex/locals.scm rename to queries/heex/locals.scm index cfa239e5f..4371bc979 100644 --- a/runtime/queries/heex/locals.scm +++ b/queries/heex/locals.scm @@ -3,11 +3,11 @@ (component_name) (slot_name) (tag_name) -] @local.reference +] @reference ; Create a new scope within each HEEx tag, component, and slot [ (component) (slot) (tag) -] @local.scope +] @scope diff --git a/queries/help/highlights.scm b/queries/help/highlights.scm new file mode 100644 index 000000000..c0d88301b --- /dev/null +++ b/queries/help/highlights.scm @@ -0,0 +1,25 @@ +(h1) @text.title +(h2) @text.title +(h3) @text.title +(column_heading) @text.title +(column_heading + "~" @conceal (#set! conceal "")) +(tag + "*" @conceal (#set! conceal "") + text: (_) @label) +(taglink + "|" @conceal (#set! conceal "") + text: (_) @text.reference) +(optionlink + text: (_) @text.reference) +(codespan + "`" @conceal (#set! conceal "") + text: (_) @text.literal) +(codeblock) @text.literal +(codeblock + [">" (language)] @conceal (#set! conceal "")) +(block + "<" @conceal (#set! conceal "")) +(argument) @parameter +(keycode) @string.special +(url) @text.uri diff --git a/queries/help/injections.scm b/queries/help/injections.scm new file mode 100644 index 000000000..09bbe44e8 --- /dev/null +++ b/queries/help/injections.scm @@ -0,0 +1,3 @@ +(codeblock + (language) @language + (code) @content) diff --git a/runtime/queries/hjson/folds.scm b/queries/hjson/folds.scm similarity index 100% rename from runtime/queries/hjson/folds.scm rename to queries/hjson/folds.scm diff --git a/runtime/queries/hjson/highlights.scm b/queries/hjson/highlights.scm similarity index 67% rename from runtime/queries/hjson/highlights.scm rename to queries/hjson/highlights.scm index 8333d8fe5..c8eed139f 100644 --- a/runtime/queries/hjson/highlights.scm +++ b/queries/hjson/highlights.scm @@ -1,28 +1,16 @@ (true) @boolean - (false) @boolean - (null) @constant.builtin - (number) @number - -(pair - key: (string) @label) - -(pair - value: (string) @string) - -(array - (string) @string) - +(pair key: (string) @label) +(pair value: (string) @string) +(array (string) @string) ; (string_content (escape_sequence) @string.escape) +(ERROR) @error ; "," @punctuation.delimiter "[" @punctuation.bracket - "]" @punctuation.bracket - "{" @punctuation.bracket - "}" @punctuation.bracket -(comment) @comment @spell +(comment) @comment diff --git a/queries/hjson/indents.scm b/queries/hjson/indents.scm new file mode 100644 index 000000000..26a42eeda --- /dev/null +++ b/queries/hjson/indents.scm @@ -0,0 +1,3 @@ +; inherits: json + +(comment) @ignore diff --git a/queries/hjson/injections.scm b/queries/hjson/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/hjson/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/runtime/queries/hjson/locals.scm b/queries/hjson/locals.scm similarity index 100% rename from runtime/queries/hjson/locals.scm rename to queries/hjson/locals.scm diff --git a/runtime/queries/hlsl/folds.scm b/queries/hlsl/folds.scm similarity index 100% rename from runtime/queries/hlsl/folds.scm rename to queries/hlsl/folds.scm diff --git a/runtime/queries/hlsl/highlights.scm b/queries/hlsl/highlights.scm similarity index 69% rename from runtime/queries/hlsl/highlights.scm rename to queries/hlsl/highlights.scm index 839d8d79a..68e9e44bd 100644 --- a/runtime/queries/hlsl/highlights.scm +++ b/queries/hlsl/highlights.scm @@ -24,15 +24,12 @@ "triangleadj" "lineadj" "triangle" -] @keyword.modifier +] @type.qualifier -((identifier) @variable.builtin - (#lua-match? @variable.builtin "^SV_")) +( + (identifier) @variable.builtin + (#lua-match? @variable.builtin "^SV_") +) (hlsl_attribute) @attribute - -(hlsl_attribute - [ - "[" - "]" - ] @attribute) +(hlsl_attribute ["[" "]"] @attribute) diff --git a/runtime/queries/hlsl/indents.scm b/queries/hlsl/indents.scm similarity index 100% rename from runtime/queries/hlsl/indents.scm rename to queries/hlsl/indents.scm diff --git a/queries/hlsl/injections.scm b/queries/hlsl/injections.scm new file mode 100644 index 000000000..537ae542d --- /dev/null +++ b/queries/hlsl/injections.scm @@ -0,0 +1,3 @@ +(preproc_arg) @hlsl + +(comment) @comment diff --git a/runtime/queries/hlsl/locals.scm b/queries/hlsl/locals.scm similarity index 100% rename from runtime/queries/hlsl/locals.scm rename to queries/hlsl/locals.scm diff --git a/queries/hocon/highlights.scm b/queries/hocon/highlights.scm new file mode 100644 index 000000000..3fb8249a9 --- /dev/null +++ b/queries/hocon/highlights.scm @@ -0,0 +1,37 @@ +(comment) @comment + +(null) @constant.builtin +[ (true) (false) ] @boolean +(number) @number +(unit) @keyword +(string) @string +(multiline_string) @string +(string (escape_sequence) @string.escape) +(unquoted_string) @string + +[ "url" + "file" + "classpath" + "required" +] @keyword + +(include "include" @include) + +(substitution ["${" "${?" "}"] @punctuation.special) +(substitution (_) @field) + +(path (_) @field) +(value [":" "=" "+=" ] @operator) + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +[ "," ] @punctuation.delimiter +(unquoted_path "." @punctuation.delimiter) + diff --git a/queries/hocon/injections.scm b/queries/hocon/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/hocon/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/runtime/queries/html/folds.scm b/queries/html/folds.scm similarity index 100% rename from runtime/queries/html/folds.scm rename to queries/html/folds.scm diff --git a/runtime/queries/html/highlights.scm b/queries/html/highlights.scm similarity index 68% rename from runtime/queries/html/highlights.scm rename to queries/html/highlights.scm index 4e2371d64..6da261c0a 100644 --- a/runtime/queries/html/highlights.scm +++ b/queries/html/highlights.scm @@ -3,5 +3,3 @@ (doctype) @constant "" + "" +] @tag.delimiter + +"=" @operator diff --git a/queries/html_tags/indents.scm b/queries/html_tags/indents.scm new file mode 100644 index 000000000..7b9d6afe1 --- /dev/null +++ b/queries/html_tags/indents.scm @@ -0,0 +1,11 @@ +[ + (element) +] @indent + +[ + (end_tag) + ">" + "/>" +] @branch + +(comment) @ignore diff --git a/queries/html_tags/injections.scm b/queries/html_tags/injections.scm new file mode 100644 index 000000000..80c0d2a4a --- /dev/null +++ b/queries/html_tags/injections.scm @@ -0,0 +1,7 @@ +((style_element + (raw_text) @css)) + +((script_element + (raw_text) @javascript)) + +(comment) @comment diff --git a/queries/http/highlights.scm b/queries/http/highlights.scm new file mode 100644 index 000000000..f5a08813b --- /dev/null +++ b/queries/http/highlights.scm @@ -0,0 +1,19 @@ +; inherits: json + +; Display errors +(ERROR) @error + +; Comments +(comment) @comment + +(request + method: (method) @keyword + url: (url) @text.uri) + +(header + name: (name) @constant + value: (value)) + +; rest.nvim Neovim plugin specific features +(external_body + json_file: (json_file) @text.uri) @keyword diff --git a/queries/http/injections.scm b/queries/http/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/http/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/queries/java/highlights.scm b/queries/java/highlights.scm new file mode 100644 index 000000000..63cb01237 --- /dev/null +++ b/queries/java/highlights.scm @@ -0,0 +1,274 @@ +; CREDITS @maxbrunsfeld (maxbrunsfeld@gmail.com) + +; Variables + +(identifier) @variable + +; Methods + +(method_declaration + name: (identifier) @method) +(method_invocation + name: (identifier) @method.call) + +(super) @function.builtin + +; Parameters +(formal_parameter + name: (identifier) @parameter) +(catch_formal_parameter + name: (identifier) @parameter) + +(spread_parameter + (variable_declarator) @parameter) ; int... foo + +;; Lambda parameter +(inferred_parameters (identifier) @parameter) ; (x,y) -> ... +(lambda_expression + parameters: (identifier) @parameter) ; x -> ... + + +; Annotations + + +(annotation + name: (identifier) @attribute) +(marker_annotation + name: (identifier) @attribute) + + +; Operators + +[ +"@" +"+" +":" +"++" +"-" +"--" +"&" +"&&" +"|" +"||" +"!=" +"==" +"*" +"/" +"%" +"<" +"<=" +">" +">=" +"=" +"-=" +"+=" +"*=" +"/=" +"%=" +"->" +"^" +"^=" +"&=" +"|=" +"~" +">>" +">>>" +"<<" +"::" +] @operator + +; Types + +(interface_declaration + name: (identifier) @type) +(class_declaration + name: (identifier) @type) +(record_declaration + name: (identifier) @type) +(enum_declaration + name: (identifier) @type) +(constructor_declaration + name: (identifier) @type) +(type_identifier) @type +((method_invocation + object: (identifier) @type) + (#lua-match? @type "^[A-Z]")) +((method_reference + . (identifier) @type) + (#lua-match? @type "^[A-Z]")) + + + +((field_access + object: (identifier) @type) + (#lua-match? @type "^[A-Z]")) +((scoped_identifier + scope: (identifier) @type) + (#lua-match? @type "^[A-Z]")) + +; Fields + +(field_declaration + declarator: (variable_declarator) @field) + +(field_access + field: (identifier) @field) + +[ +(boolean_type) +(integral_type) +(floating_point_type) +(void_type) +] @type.builtin + +; Variables + +((identifier) @constant + (#lua-match? @constant "^[A-Z_][A-Z%d_]+$")) + +(this) @variable.builtin + +; Literals + +[ +(hex_integer_literal) +(decimal_integer_literal) +(octal_integer_literal) +(binary_integer_literal) +] @number + +[ +(decimal_floating_point_literal) +(hex_floating_point_literal) +] @float + +(character_literal) @character +[(string_literal) (text_block)] @string +(null_literal) @constant.builtin + +[ + (line_comment) + (block_comment) +] @comment @spell + +[ +(true) +(false) +] @boolean + +; Keywords + +[ +"assert" +"break" +"class" +"record" +"continue" +"default" +"enum" +"exports" +"extends" +"implements" +"instanceof" +"interface" +"module" +"opens" +"package" +"permits" +"provides" +"requires" +"to" +"uses" +"with" +] @keyword + +(synchronized_statement + "synchronized" @keyword) + +[ +"abstract" +"final" +"native" +"non-sealed" +"open" +"private" +"protected" +"public" +"sealed" +"static" +"strictfp" +"transitive" +] @type.qualifier + +(modifiers + "synchronized" @type.qualifier) + +[ +"transient" +"volatile" +] @storageclass + +[ +"return" +"yield" +] @keyword.return + +[ + "new" +] @keyword.operator + +; Conditionals + +[ +"if" +"else" +"switch" +"case" +] @conditional + +(ternary_expression ["?" ":"] @conditional.ternary) + +; + +[ +"for" +"while" +"do" +] @repeat + +; Includes + +"import" @include +"package" @include + +; Punctuation + +[ +";" +"." +"..." +"," +] @punctuation.delimiter + +[ +"[" +"]" +"{" +"}" +"(" +")" +] @punctuation.bracket + +; Exceptions + +[ +"throw" +"throws" +"finally" +"try" +"catch" +] @exception + +; Labels +(labeled_statement + (identifier) @label) diff --git a/queries/java/indents.scm b/queries/java/indents.scm new file mode 100644 index 000000000..8e5375486 --- /dev/null +++ b/queries/java/indents.scm @@ -0,0 +1,34 @@ +[ + (class_body) + (enum_body) + (interface_body) + (constructor_declaration) + (constructor_body) + (block) + (switch_block) + (array_initializer) + (argument_list) + (formal_parameters) +] @indent + +(expression_statement (method_invocation) @indent) + +[ + "(" + ")" + "{" + "}" + "[" + "]" +] @branch + +[ + "}" +] @indent_end + +(line_comment) @ignore + +[ + (ERROR) + (block_comment) +] @auto diff --git a/queries/java/injections.scm b/queries/java/injections.scm new file mode 100644 index 000000000..e4fd85f1c --- /dev/null +++ b/queries/java/injections.scm @@ -0,0 +1 @@ +[(block_comment) (line_comment)] @comment diff --git a/queries/java/locals.scm b/queries/java/locals.scm new file mode 100644 index 000000000..a7a624289 --- /dev/null +++ b/queries/java/locals.scm @@ -0,0 +1,77 @@ +; SCOPES +; declarations +(program) @scope +(class_declaration + body: (_) @scope) +(record_declaration + body: (_) @scope) +(enum_declaration + body: (_) @scope) +(lambda_expression) @scope +(enhanced_for_statement) @scope + +; block +(block) @scope + +; if/else +(if_statement) @scope ; if+else +(if_statement + consequence: (_) @scope) ; if body in case there are no braces +(if_statement + alternative: (_) @scope) ; else body in case there are no braces + +; try/catch +(try_statement) @scope ; covers try+catch, individual try and catch are covered by (block) +(catch_clause) @scope ; needed because `Exception` variable + +; loops +(for_statement) @scope ; whole for_statement because loop iterator variable +(for_statement ; "for" body in case there are no braces + body: (_) @scope) +(do_statement + body: (_) @scope) +(while_statement + body: (_) @scope) + +; Functions + +(constructor_declaration) @scope +(method_declaration) @scope + + +; DEFINITIONS +(package_declaration + (identifier) @definition.namespace) +(class_declaration + name: (identifier) @definition.type) +(record_declaration + name: (identifier) @definition.type) +(enum_declaration + name: (identifier) @definition.enum) +(method_declaration + name: (identifier) @definition.method) + +(local_variable_declaration + declarator: (variable_declarator + name: (identifier) @definition.var)) +(formal_parameter + name: (identifier) @definition.var) +(catch_formal_parameter + name: (identifier) @definition.var) +(inferred_parameters (identifier) @definition.var) ; (x,y) -> ... +(lambda_expression + parameters: (identifier) @definition.var) ; x -> ... +(enhanced_for_statement ; for (var item : items) { + name: (identifier) @definition.var) + +((scoped_identifier + (identifier) @definition.import) + (#has-ancestor? @definition.import import_declaration)) + +(field_declaration + declarator: (variable_declarator + name: (identifier) @definition.field)) + +; REFERENCES +(identifier) @reference +(type_identifier) @reference diff --git a/runtime/queries/javascript/folds.scm b/queries/javascript/folds.scm similarity index 100% rename from runtime/queries/javascript/folds.scm rename to queries/javascript/folds.scm diff --git a/queries/javascript/highlights.scm b/queries/javascript/highlights.scm new file mode 100644 index 000000000..b62679c4b --- /dev/null +++ b/queries/javascript/highlights.scm @@ -0,0 +1,36 @@ +; inherits: ecma,jsx + +;;; Parameters +(formal_parameters (identifier) @parameter) + +(formal_parameters + (rest_pattern + (identifier) @parameter)) + +;; ({ a }) => null +(formal_parameters + (object_pattern + (shorthand_property_identifier_pattern) @parameter)) + +;; ({ a: b }) => null +(formal_parameters + (object_pattern + (pair_pattern + value: (identifier) @parameter))) + +;; ([ a ]) => null +(formal_parameters + (array_pattern + (identifier) @parameter)) + +;; a => null +(arrow_function + parameter: (identifier) @parameter) + +;; optional parameters +(formal_parameters + (assignment_pattern + left: (identifier) @parameter)) + +;; punctuation +(optional_chain) @punctuation.delimiter diff --git a/runtime/queries/javascript/indents.scm b/queries/javascript/indents.scm similarity index 100% rename from runtime/queries/javascript/indents.scm rename to queries/javascript/indents.scm diff --git a/runtime/queries/javascript/injections.scm b/queries/javascript/injections.scm similarity index 100% rename from runtime/queries/javascript/injections.scm rename to queries/javascript/injections.scm diff --git a/queries/javascript/locals.scm b/queries/javascript/locals.scm new file mode 100644 index 000000000..098f18af6 --- /dev/null +++ b/queries/javascript/locals.scm @@ -0,0 +1,63 @@ +; inherits: ecma,jsx + +; Both properties are matched here. +; +; class Foo { +; this.#bar = "baz"; +; this.quuz = "qux"; +; } +(field_definition + property: [(property_identifier) (private_property_identifier)] @definition.var) + +; this.foo = "bar" +(assignment_expression + left: (member_expression + object: (this) + property: (property_identifier) @definition.var)) + +(formal_parameters + (identifier) @definition.parameter) + +; function(arg = []) { +(formal_parameters + (assignment_pattern + left: (identifier) @definition.parameter)) + +; x => x +(arrow_function + parameter: (identifier) @definition.parameter) + +;; ({ a }) => null +(formal_parameters + (object_pattern + (shorthand_property_identifier_pattern) @definition.parameter)) + +;; ({ a: b }) => null +(formal_parameters + (object_pattern + (pair_pattern + value: (identifier) @definition.parameter))) + +;; ([ a ]) => null +(formal_parameters + (array_pattern + (identifier) @definition.parameter)) + +(formal_parameters + (rest_pattern + (identifier) @definition.parameter)) + +; Both methods are matched here. +; +; class Foo { +; #bar(x) { x } +; baz(y) { y } +; } +(method_definition + ([(property_identifier) (private_property_identifier)] @definition.function) + (#set! definition.var.scope parent)) + +; this.foo() +(member_expression + object: (this) + property: (property_identifier) @reference) diff --git a/queries/jq/highlights.scm b/queries/jq/highlights.scm new file mode 100644 index 000000000..0793e159e --- /dev/null +++ b/queries/jq/highlights.scm @@ -0,0 +1,329 @@ +; Variables + +(variable) @variable + +((variable) @constant.builtin + (#eq? @constant.builtin "$ENV")) + +((variable) @constant.macro + (#eq? @constant.macro "$__loc__")) + +; Properties + +(index + (identifier) @property) + +; Labels + +(query + label: (variable) @label) + +(query + break_statement: (variable) @label) + +; Literals + +(number) @number + +(string) @string + +[ + "true" + "false" +] @boolean + +("null") @type.builtin + +; Interpolation + +["\\(" ")"] @character.special + +; Format + +(format) @attribute + +; Functions + +(funcdef + (identifier) @function) + +(funcdefargs + (identifier) @parameter) + +[ + "reduce" + "foreach" +] @function.builtin + +; jq -n 'builtins | map(split("/")[0]) | unique | .[]' +((funcname) @function.builtin + (#any-of? @function.builtin + "IN" + "INDEX" + "JOIN" + "acos" + "acosh" + "add" + "all" + "any" + "arrays" + "ascii_downcase" + "ascii_upcase" + "asin" + "asinh" + "atan" + "atan2" + "atanh" + "booleans" + "bsearch" + "builtins" + "capture" + "cbrt" + "ceil" + "combinations" + "contains" + "copysign" + "cos" + "cosh" + "debug" + "del" + "delpaths" + "drem" + "empty" + "endswith" + "env" + "erf" + "erfc" + "error" + "exp" + "exp10" + "exp2" + "explode" + "expm1" + "fabs" + "fdim" + "finites" + "first" + "flatten" + "floor" + "fma" + "fmax" + "fmin" + "fmod" + "format" + "frexp" + "from_entries" + "fromdate" + "fromdateiso8601" + "fromjson" + "fromstream" + "gamma" + "get_jq_origin" + "get_prog_origin" + "get_search_list" + "getpath" + "gmtime" + "group_by" + "gsub" + "halt" + "halt_error" + "has" + "hypot" + "implode" + "in" + "index" + "indices" + "infinite" + "input" + "input_filename" + "input_line_number" + "inputs" + "inside" + "isempty" + "isfinite" + "isinfinite" + "isnan" + "isnormal" + "iterables" + "j0" + "j1" + "jn" + "join" + "keys" + "keys_unsorted" + "last" + "ldexp" + "leaf_paths" + "length" + "lgamma" + "lgamma_r" + "limit" + "localtime" + "log" + "log10" + "log1p" + "log2" + "logb" + "ltrimstr" + "map" + "map_values" + "match" + "max" + "max_by" + "min" + "min_by" + "mktime" + "modf" + "modulemeta" + "nan" + "nearbyint" + "nextafter" + "nexttoward" + "normals" + "not" + "now" + "nth" + "nulls" + "numbers" + "objects" + "path" + "paths" + "pow" + "pow10" + "range" + "recurse" + "recurse_down" + "remainder" + "repeat" + "reverse" + "rindex" + "rint" + "round" + "rtrimstr" + "scalars" + "scalars_or_empty" + "scalb" + "scalbln" + "scan" + "select" + "setpath" + "significand" + "sin" + "sinh" + "sort" + "sort_by" + "split" + "splits" + "sqrt" + "startswith" + "stderr" + "strflocaltime" + "strftime" + "strings" + "strptime" + "sub" + "tan" + "tanh" + "test" + "tgamma" + "to_entries" + "todate" + "todateiso8601" + "tojson" + "tonumber" + "tostream" + "tostring" + "transpose" + "trunc" + "truncate_stream" + "type" + "unique" + "unique_by" + "until" + "utf8bytelength" + "values" + "walk" + "while" + "with_entries" + "y0" + "y1" + "yn")) + +; Keywords + +[ + "def" + "as" + "label" + "module" + "break" +] @keyword + +[ + "import" + "include" +] @include + +[ + "if" + "then" + "else" + "end" +] @conditional + +[ + "try" + "catch" +] @exception + +[ + "or" + "and" +] @keyword.operator + +; Operators + +[ + "." + "==" + "!=" + ">" + ">=" + "<=" + "<" + "=" + "+" + "-" + "*" + "/" + "%" + "+=" + "-=" + "*=" + "/=" + "%=" + "//=" + "|" + "?" + "//" + "?//" + (recurse) ; ".." +] @operator + +; Punctuation + +[ + ";" + "," + ":" +] @punctuation.delimiter + +[ + "[" "]" + "{" "}" + "(" ")" +] @punctuation.bracket + +; Comments + +(comment) @comment @spell diff --git a/queries/jq/injections.scm b/queries/jq/injections.scm new file mode 100644 index 000000000..5b3913967 --- /dev/null +++ b/queries/jq/injections.scm @@ -0,0 +1,31 @@ +(comment) @comment + +; test(val) +(query + ((funcname) @_function + (#any-of? @_function + "test" + "match" + "capture" + "scan" + "split" + "splits" + "sub" + "gsub")) + (args . (query (string) @regex))) + + +; test(regex; flags) +(query + ((funcname) @_function + (#any-of? @_function + "test" + "match" + "capture" + "scan" + "split" + "splits" + "sub" + "gsub")) + (args . (args + (query (string) @regex)))) diff --git a/queries/jsdoc/highlights.scm b/queries/jsdoc/highlights.scm new file mode 100644 index 000000000..4b4266c9f --- /dev/null +++ b/queries/jsdoc/highlights.scm @@ -0,0 +1,2 @@ +(tag_name) @keyword +(type) @type diff --git a/runtime/queries/json/folds.scm b/queries/json/folds.scm similarity index 100% rename from runtime/queries/json/folds.scm rename to queries/json/folds.scm diff --git a/queries/json/highlights.scm b/queries/json/highlights.scm new file mode 100644 index 000000000..f41b44a5a --- /dev/null +++ b/queries/json/highlights.scm @@ -0,0 +1,17 @@ +(true) @boolean +(false) @boolean +(null) @constant.builtin +(number) @number +(pair key: (string) @label) +(pair value: (string) @string) +(array (string) @string) +(string_content (escape_sequence) @string.escape) +(string_content) @spell +(ERROR) @error +["," ":"] @punctuation.delimiter +"[" @punctuation.bracket +"]" @punctuation.bracket +"{" @punctuation.bracket +"}" @punctuation.bracket + +(("\"" @conceal) (#set! conceal "")) diff --git a/queries/json/indents.scm b/queries/json/indents.scm new file mode 100644 index 000000000..0345b945b --- /dev/null +++ b/queries/json/indents.scm @@ -0,0 +1,9 @@ +[ + (object) + (array) +] @indent + +[ + "}" + "]" +] @branch diff --git a/runtime/queries/hocon/folds.scm b/queries/json/locals.scm similarity index 71% rename from runtime/queries/hocon/folds.scm rename to queries/json/locals.scm index cc8a231a4..6609a2d22 100644 --- a/runtime/queries/hocon/folds.scm +++ b/queries/json/locals.scm @@ -1,4 +1,4 @@ [ (object) (array) -] @fold +] @scope diff --git a/queries/json5/highlights.scm b/queries/json5/highlights.scm new file mode 100644 index 000000000..4e41971ba --- /dev/null +++ b/queries/json5/highlights.scm @@ -0,0 +1,17 @@ +[ + "true" + "false" +] @boolean + +"null" @constant + +(string) @string + +(number) @number + +(comment) @comment + +(member + name: (_) @keyword) + +(ERROR) @error diff --git a/queries/json5/injections.scm b/queries/json5/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/json5/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/queries/jsonc/folds.scm b/queries/jsonc/folds.scm new file mode 100644 index 000000000..41269219e --- /dev/null +++ b/queries/jsonc/folds.scm @@ -0,0 +1 @@ +; inherits: json diff --git a/queries/jsonc/highlights.scm b/queries/jsonc/highlights.scm new file mode 100644 index 000000000..e50112155 --- /dev/null +++ b/queries/jsonc/highlights.scm @@ -0,0 +1,3 @@ +; inherits: json + +(comment) @comment @spell diff --git a/queries/jsonc/indents.scm b/queries/jsonc/indents.scm new file mode 100644 index 000000000..26a42eeda --- /dev/null +++ b/queries/jsonc/indents.scm @@ -0,0 +1,3 @@ +; inherits: json + +(comment) @ignore diff --git a/queries/jsonc/injections.scm b/queries/jsonc/injections.scm new file mode 100644 index 000000000..4bb7d675d --- /dev/null +++ b/queries/jsonc/injections.scm @@ -0,0 +1 @@ +(comment) @comment diff --git a/queries/jsonc/locals.scm b/queries/jsonc/locals.scm new file mode 100644 index 000000000..41269219e --- /dev/null +++ b/queries/jsonc/locals.scm @@ -0,0 +1 @@ +; inherits: json diff --git a/queries/jsonnet/highlights.scm b/queries/jsonnet/highlights.scm new file mode 100644 index 000000000..eb8d22be9 --- /dev/null +++ b/queries/jsonnet/highlights.scm @@ -0,0 +1,76 @@ +[ + (true) + (false) +] @boolean + +(comment) @comment +(id) @variable +(import) @include +(null) @constant.builtin +(number) @number +(string) @string + +(fieldname (id) @label) + +[ + "[" + "]" + "{" + "}" + "(" + ")" +] @punctuation.bracket + +[ + "." + "," + ";" + ":" + "::" + ":::" +] @punctuation.delimiter + +(expr + operator: (_) @operator) +[ + "+" + "=" +] @operator + +"in" @keyword.operator + +[ + (local) + "assert" +] @keyword + +[ + "else" + "if" + "then" +] @conditional + +[ + (dollar) + (self) +] @variable.builtin +((id) @variable.builtin + (#eq? @variable.builtin "std")) + +; Function declaration +(bind + function: (id) @function + params: (params + (param + identifier: (id) @parameter))) + +; Function call +(expr + (expr (id) @function.call) + "(" + (args + (named_argument + (id) @parameter))? + ")") + +(ERROR) @error diff --git a/runtime/queries/jsx/folds.scm b/queries/jsx/folds.scm similarity index 100% rename from runtime/queries/jsx/folds.scm rename to queries/jsx/folds.scm diff --git a/queries/jsx/highlights.scm b/queries/jsx/highlights.scm new file mode 100644 index 000000000..1f19c6b2a --- /dev/null +++ b/queries/jsx/highlights.scm @@ -0,0 +1,36 @@ +(jsx_element + open_tag: (jsx_opening_element ["<" ">"] @tag.delimiter)) +(jsx_element + close_tag: (jsx_closing_element ["<" "/" ">"] @tag.delimiter)) +(jsx_self_closing_element ["/" ">" "<"] @tag.delimiter) +(jsx_fragment [">" "<" "/"] @tag.delimiter) +(jsx_attribute (property_identifier) @tag.attribute) + +(jsx_opening_element + name: (identifier) @tag) + +(jsx_closing_element + name: (identifier) @tag) + +(jsx_self_closing_element + name: (identifier) @tag) + +(jsx_opening_element ((identifier) @constructor + (#lua-match? @constructor "^[A-Z]"))) + +; Handle the dot operator effectively - +(jsx_opening_element ((nested_identifier (identifier) @tag (identifier) @constructor))) + +(jsx_closing_element ((identifier) @constructor + (#lua-match? @constructor "^[A-Z]"))) + +; Handle the dot operator effectively - +(jsx_closing_element ((nested_identifier (identifier) @tag (identifier) @constructor))) + +(jsx_self_closing_element ((identifier) @constructor + (#lua-match? @constructor "^[A-Z]"))) + +; Handle the dot operator effectively - +(jsx_self_closing_element ((nested_identifier (identifier) @tag (identifier) @constructor))) + +(jsx_text) @none diff --git a/queries/jsx/indents.scm b/queries/jsx/indents.scm new file mode 100644 index 000000000..d1a12be9c --- /dev/null +++ b/queries/jsx/indents.scm @@ -0,0 +1,12 @@ +[ + (jsx_fragment) + (jsx_element) + (jsx_self_closing_element) +] @indent + +(parenthesized_expression) @indent + +[ + (jsx_closing_element) + ">" +] @branch diff --git a/queries/jsx/injections.scm b/queries/jsx/injections.scm new file mode 100644 index 000000000..3a96931b0 --- /dev/null +++ b/queries/jsx/injections.scm @@ -0,0 +1,8 @@ +; Styled Jsx -; -; Add "lang" to predicate check so that vue/svelte can inherit this -; without having this element being captured twice -((style_element - (start_tag) @_no_type_lang - (raw_text) @injection.content) - (#not-lua-match? @_no_type_lang "%slang%s*=") - (#not-lua-match? @_no_type_lang "%stype%s*=") - (#set! injection.language "css")) - -((style_element - (start_tag - (attribute - (attribute_name) @_type - (quoted_attribute_value - (attribute_value) @_css))) - (raw_text) @injection.content) - (#eq? @_type "type") - (#eq? @_css "text/css") - (#set! injection.language "css")) - -; -; -((script_element - (start_tag) @_no_type_lang - (raw_text) @injection.content) - (#not-lua-match? @_no_type_lang "%slang%s*=") - (#not-lua-match? @_no_type_lang "%stype%s*=") - (#set! injection.language "javascript")) - -; - diff --git a/tests/indent/html/self_closing_tag.html b/tests/indent/html/self_closing_tag.html deleted file mode 100644 index 79376b83d..000000000 --- a/tests/indent/html/self_closing_tag.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - -
- - - - {switch state { - | Active => - switch ReactDOM.querySelector("body") { - | Some(element) => - ReactDOM.createPortal( - scrollY} - transformItems={transformItems} - hitComponent=hit - /> - element, - ) - | None => React.null - } - | Inactive => React.null - }} - -} - -let comparable = (type key, ~cmp) => { - module N = MakeComparable({ - type t = key - let cmp = cmp - }) - module(N: Comparable with type t = key) -} - - - - {description->React.string} - children - diff --git a/tests/indent/rescript/conditional.res b/tests/indent/rescript/conditional.res deleted file mode 100644 index db8328f26..000000000 --- a/tests/indent/rescript/conditional.res +++ /dev/null @@ -1,104 +0,0 @@ -include UseClient -include UseQuery -include UseMutation -include UseSubscription - -type hookResponse<'ret> = Types.Hooks.hookResponse<'ret> = { - operation: Types.operation, - fetching: bool, - data: option<'ret>, - error: option, - response: Types.Hooks.response<'ret>, - extensions: option, - stale: bool, -} - -Js.Array2.slice(~start=0, ~end_=Js.Array2.length(moduleRoute) - 1) - -let pathModule = Path.join([dir, version, `${moduleName}.json`]) - -let {Api.LocMsg.row: row, column, shortMsg} = locMsg - -let message = `${"error"->red}: failed to compile examples from ${kind} ${test.id->cyan}\n${errorMessage}` - -let version = (evt->ReactEvent.Form.target)["value"] - -let rehypePlugins = - [Rehype.WithOptions([Plugin(Rehype.slug), SlugOption({prefix: slugPrefix ++ "-"})])]->Some - -module Item = { - type t = { - name: string, - sellIn: int, - quality: int, - } - - let make = (~name, ~sellIn, ~quality): t => { - name, - sellIn, - quality, - } -} - -let updateQuality = (items: array) => { - items->Js.Array2.map(item => { - let newItem = ref(item) - - call( - asdf, - asdf - ) - - if ( - newItem.contents.name != "Aged Brie" && 5 > 2 && - newItem.contents.name != "Backstage passes to a TAFKAL80ETC concert" - ) { - if newItem.contents.quality > 0 { - if newItem.contents.name != "Sulfuras, Hand of Ragnaros" { - newItem := {...newItem.contents, quality: newItem.contents.quality - 1} - } - } - } else if newItem.contents.quality < 50 { - newItem := {...newItem.contents, quality: newItem.contents.quality + 1} - - if newItem.contents.name == "Backstage passes to a TAFKAL80ETC concert" { - if newItem.contents.sellIn < 11 { - if newItem.contents.quality < 50 { - newItem := {...newItem.contents, quality: newItem.contents.quality + 1} - } - } - - if newItem.contents.sellIn < 6 { - if newItem.contents.quality < 50 { - newItem := {...newItem.contents, quality: newItem.contents.quality + 1} - } - } - } - } - - if newItem.contents.name != "Sulfuras, Hand of Ragnaros" { - newItem := {...newItem.contents, sellIn: newItem.contents.sellIn - 1} - } - - if newItem.contents.sellIn < 0 { - if newItem.contents.name != "Aged Brie" { - if newItem.contents.name != "Backstage passes to a TAFKAL80ETC concert" { - if newItem.contents.quality > 0 { - if newItem.contents.name != "Sulfuras, Hand of Ragnaros" { - newItem := {...newItem.contents, quality: newItem.contents.quality - 1} - } - } - } else { - newItem := { - ...newItem.contents, - quality: newItem.contents.quality - newItem.contents.quality, - } - } - } else if newItem.contents.quality < 50 { - newItem := {...newItem.contents, quality: newItem.contents.quality + 1} - } - } - - newItem.contents - }) -} diff --git a/tests/indent/rescript_spec.lua b/tests/indent/rescript_spec.lua deleted file mode 100644 index e97cd1e8b..000000000 --- a/tests/indent/rescript_spec.lua +++ /dev/null @@ -1,33 +0,0 @@ -local Runner = require('tests.indent.common').Runner - -local run = Runner:new(it, 'tests/indent/rescript', { - tabstop = 2, - shiftwidth = 2, - softtabstop = 0, - expandtab = true, -}) - -describe('indent ReScript:', function() - describe('whole file:', function() - run:whole_file('.', {}) - end) - - describe('new line:', function() - run:new_line('basic.res', { on_line = 5, text = 'x', indent = 0 }) - run:new_line('basic.res', { on_line = 9, text = '"another": here,', indent = 2 }) - run:new_line('basic.res', { on_line = 10, text = '}', indent = 0 }) - run:new_line('basic.res', { on_line = 14, text = '~test: test,', indent = 2 }) - run:new_line('basic.res', { on_line = 18, text = 'x', indent = 0 }) - - run:new_line('complex.res', { on_line = 3, text = 'x', indent = 2 }) - run:new_line('complex.res', { on_line = 5, text = 'x', indent = 4 }) - run:new_line('complex.res', { on_line = 17, text = '|', indent = 10 }) - run:new_line('complex.res', { on_line = 25, text = 'x', indent = 2 }) - run:new_line('complex.res', { on_line = 60, text = 'x', indent = 6 }) - run:new_line('complex.res', { on_line = 120, text = 'x', indent = 14 }) - run:new_line('complex.res', { on_line = 136, text = 'x', indent = 2 }) - - run:new_line('conditional.res', { on_line = 6, text = 'test: bool,', indent = 2 }) - run:new_line('conditional.res', { on_line = 95, text = 'x', indent = 10 }) - end) -end) diff --git a/tests/indent/ruby/indent-ensure.rb b/tests/indent/ruby/indent-ensure.rb deleted file mode 100644 index fce277994..000000000 --- a/tests/indent/ruby/indent-ensure.rb +++ /dev/null @@ -1,2 +0,0 @@ -begin -end diff --git a/tests/indent/ruby/indent-rescue.rb b/tests/indent/ruby/indent-rescue.rb deleted file mode 100644 index fce277994..000000000 --- a/tests/indent/ruby/indent-rescue.rb +++ /dev/null @@ -1,2 +0,0 @@ -begin -end diff --git a/tests/indent/ruby/indent-square-brackets.rb b/tests/indent/ruby/indent-square-brackets.rb deleted file mode 100644 index 8746d222d..000000000 --- a/tests/indent/ruby/indent-square-brackets.rb +++ /dev/null @@ -1,5 +0,0 @@ -def indent_square_brackets - [ - [] - ] -end diff --git a/tests/indent/ruby_spec.lua b/tests/indent/ruby_spec.lua index 4dcd4d0fa..277d02bf0 100644 --- a/tests/indent/ruby_spec.lua +++ b/tests/indent/ruby_spec.lua @@ -1,22 +1,20 @@ -local Runner = require('tests.indent.common').Runner +local Runner = require("tests.indent.common").Runner -local run = Runner:new(it, 'tests/indent/ruby', { +local run = Runner:new(it, "tests/indent/ruby", { shiftwidth = 2, expandtab = true, }) -describe('indent Ruby:', function() - describe('whole file:', function() - run:whole_file('.', { - expected_failures = { './period-issue-3364.rb' }, +describe("indent Ruby:", function() + describe("whole file:", function() + run:whole_file(".", { + expected_failures = { "./period-issue-3364.rb" }, }) end) - describe('new line:', function() - run:new_line('indent-unless.rb', { on_line = 1, text = 'stmt', indent = 2 }) - run:new_line('indent-assignment.rb', { on_line = 1, text = '1 +', indent = 2 }) - run:new_line('indent-parenthesized-statements.rb', { on_line = 1, text = 'stmt', indent = 2 }) - run:new_line('indent-rescue.rb', { on_line = 1, text = 'rescue', indent = 0 }) - run:new_line('indent-ensure.rb', { on_line = 1, text = 'ensure', indent = 0 }) + describe("new line:", function() + run:new_line("indent-unless.rb", { on_line = 1, text = "stmt", indent = 2 }) + run:new_line("indent-assignment.rb", { on_line = 1, text = "1 +", indent = 2 }) + run:new_line("indent-parenthesized-statements.rb", { on_line = 1, text = "stmt", indent = 2 }) end) end) diff --git a/tests/indent/rust/tuple.rs b/tests/indent/rust/tuple.rs deleted file mode 100644 index 9001f77a5..000000000 --- a/tests/indent/rust/tuple.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn foo() { - for ( - a, - b - ) in c.iter() { - // ... - } -} diff --git a/tests/indent/rust_spec.lua b/tests/indent/rust_spec.lua index 3671e9ee7..795765ba5 100644 --- a/tests/indent/rust_spec.lua +++ b/tests/indent/rust_spec.lua @@ -1,66 +1,66 @@ -local Runner = require('tests.indent.common').Runner +local Runner = require("tests.indent.common").Runner -local run = Runner:new(it, 'tests/indent/rust', { +local run = Runner:new(it, "tests/indent/rust", { tabstop = 4, shiftwidth = 4, softtabstop = 0, expandtab = true, }) -describe('indent Rust:', function() - describe('whole file:', function() - run:whole_file('.') +describe("indent Rust:", function() + describe("whole file:", function() + run:whole_file "." end) - describe('new line:', function() - run:new_line('array.rs', { on_line = 2, text = '0,', indent = 4 }) - run:new_line('array.rs', { on_line = 8, text = '0,', indent = 8 }) - run:new_line('comment.rs', { on_line = 3, text = 'a', indent = '/// ' }) - run:new_line('comment.rs', { on_line = 10, text = 'a', indent = ' /// ' }) - run:new_line('cond.rs', { on_line = 11, text = 'x += 1;', indent = 12 }) - run:new_line('cond.rs', { on_line = 2, text = 'x += 1;', indent = 8 }) - run:new_line('cond.rs', { on_line = 4, text = 'x += 1;', indent = 8 }) - run:new_line('cond.rs', { on_line = 6, text = 'x += 1;', indent = 8 }) - run:new_line('cond.rs', { on_line = 8, text = 'x += 1;', indent = 4 }) - run:new_line('if_let_cond.rs', { on_line = 2, text = 'let a = 1;', indent = 8 }) - run:new_line('if_let_cond.rs', { on_line = 4, text = 'let a = 1;', indent = 8 }) - run:new_line('if_let_cond.rs', { on_line = 6, text = 'let a = 1;', indent = 4 }) - run:new_line('enum.rs', { on_line = 2, text = 'Q,', indent = 4 }) - run:new_line('enum.rs', { on_line = 4, text = 'i32,', indent = 8 }) - run:new_line('enum.rs', { on_line = 8, text = 'z: u32,', indent = 8 }) - run:new_line('enum.rs', { on_line = 11, text = 'let _x = 1;', indent = 0 }) - run:new_line('func.rs', { on_line = 1, text = 'let _x = 1;', indent = 4 }) - run:new_line('func.rs', { on_line = 3, text = 'let _x = 1;', indent = 0 }) - run:new_line('func.rs', { on_line = 6, text = 'z: i32,', indent = 4 }) - run:new_line('impl.rs', { on_line = 3, text = 'const FOO: u32 = 1;', indent = 4 }) - run:new_line('impl.rs', { on_line = 4, text = 'let _x = 1;', indent = 8 }) - run:new_line('impl.rs', { on_line = 6, text = 'let _x = 1;', indent = 4 }) - run:new_line('impl.rs', { on_line = 7, text = 'let _x = 1;', indent = 0 }) - run:new_line('loop.rs', { on_line = 10, text = 'x += 1;', indent = 8 }) - run:new_line('loop.rs', { on_line = 2, text = 'x += 1;', indent = 8 }) - run:new_line('loop.rs', { on_line = 6, text = 'x += 1;', indent = 8 }) - run:new_line('macro.rs', { on_line = 1, text = '() => {},', indent = 4 }) - run:new_line('macro.rs', { on_line = 12, text = 'B C', indent = 4 }) - run:new_line('macro.rs', { on_line = 2, text = 'struct $c;', indent = 8 }) - run:new_line('match.rs', { on_line = 2, text = '-1 => -1,', indent = 8 }) - run:new_line('match.rs', { on_line = 7, text = 'let y = 1;', indent = 12 }) - run:new_line('match.rs', { on_line = 10, text = 'let y = 1;', indent = 4 }) - run:new_line('mod.rs', { on_line = 1, text = 'const Z: i32 = 1;', indent = 4 }) - run:new_line('mod.rs', { on_line = 2, text = 'const Z: i32 = 1;', indent = 4 }) - run:new_line('mod.rs', { on_line = 6, text = 'const Z: i32 = 1;', indent = 8 }) - run:new_line('mod.rs', { on_line = 7, text = 'const Z: i32 = 1;', indent = 4 }) - run:new_line('string.rs', { on_line = 2, text = 'brave new', indent = 0 }) - run:new_line('string.rs', { on_line = 5, text = 'brave new \\', indent = 8 }) - run:new_line('string.rs', { on_line = 9, text = 'brave new \\', indent = 8 }) - run:new_line('struct.rs', { on_line = 1, text = 'z: i32,', indent = 4 }) - run:new_line('struct.rs', { on_line = 2, text = 'z: i32,', indent = 4 }) - run:new_line('struct.rs', { on_line = 4, text = 'let y = 1;', indent = 0 }) - run:new_line('trait.rs', { on_line = 4, text = 'fn baz();', indent = 4 }) - run:new_line('trait.rs', { on_line = 5, text = 'let y = 1;', indent = 0 }) - run:new_line('trait.rs', { on_line = 7, text = 'fn baz();', indent = 4 }) - run:new_line('trait.rs', { on_line = 8, text = '()', indent = 8 }) - run:new_line('where.rs', { on_line = 17, text = 'T: Debug,', indent = 4 }) - run:new_line('where.rs', { on_line = 2, text = 'T: Debug,', indent = 4 }) - run:new_line('where.rs', { on_line = 9, text = 'T: Debug,', indent = 4 }) + describe("new line:", function() + run:new_line("array.rs", { on_line = 2, text = "0,", indent = 4 }) + run:new_line("array.rs", { on_line = 8, text = "0,", indent = 8 }) + run:new_line("comment.rs", { on_line = 3, text = "a", indent = "/// " }) + run:new_line("comment.rs", { on_line = 10, text = "a", indent = " /// " }) + run:new_line("cond.rs", { on_line = 11, text = "x += 1;", indent = 12 }) + run:new_line("cond.rs", { on_line = 2, text = "x += 1;", indent = 8 }) + run:new_line("cond.rs", { on_line = 4, text = "x += 1;", indent = 8 }) + run:new_line("cond.rs", { on_line = 6, text = "x += 1;", indent = 8 }) + run:new_line("cond.rs", { on_line = 8, text = "x += 1;", indent = 4 }) + run:new_line("if_let_cond.rs", { on_line = 2, text = "let a = 1;", indent = 8 }) + run:new_line("if_let_cond.rs", { on_line = 4, text = "let a = 1;", indent = 8 }) + run:new_line("if_let_cond.rs", { on_line = 6, text = "let a = 1;", indent = 4 }) + run:new_line("enum.rs", { on_line = 2, text = "Q,", indent = 4 }) + run:new_line("enum.rs", { on_line = 4, text = "i32,", indent = 8 }) + run:new_line("enum.rs", { on_line = 8, text = "z: u32,", indent = 8 }) + run:new_line("enum.rs", { on_line = 11, text = "let _x = 1;", indent = 0 }) + run:new_line("func.rs", { on_line = 1, text = "let _x = 1;", indent = 4 }) + run:new_line("func.rs", { on_line = 3, text = "let _x = 1;", indent = 0 }) + run:new_line("func.rs", { on_line = 6, text = "z: i32,", indent = 4 }) + run:new_line("impl.rs", { on_line = 3, text = "const FOO: u32 = 1;", indent = 4 }) + run:new_line("impl.rs", { on_line = 4, text = "let _x = 1;", indent = 8 }) + run:new_line("impl.rs", { on_line = 6, text = "let _x = 1;", indent = 4 }) + run:new_line("impl.rs", { on_line = 7, text = "let _x = 1;", indent = 0 }) + run:new_line("loop.rs", { on_line = 10, text = "x += 1;", indent = 8 }) + run:new_line("loop.rs", { on_line = 2, text = "x += 1;", indent = 8 }) + run:new_line("loop.rs", { on_line = 6, text = "x += 1;", indent = 8 }) + run:new_line("macro.rs", { on_line = 1, text = "() => {},", indent = 4 }) + run:new_line("macro.rs", { on_line = 12, text = "B C", indent = 4 }) + run:new_line("macro.rs", { on_line = 2, text = "struct $c;", indent = 8 }) + run:new_line("match.rs", { on_line = 2, text = "-1 => -1,", indent = 8 }) + run:new_line("match.rs", { on_line = 7, text = "let y = 1;", indent = 12 }) + run:new_line("match.rs", { on_line = 10, text = "let y = 1;", indent = 4 }) + run:new_line("mod.rs", { on_line = 1, text = "const Z: i32 = 1;", indent = 4 }) + run:new_line("mod.rs", { on_line = 2, text = "const Z: i32 = 1;", indent = 4 }) + run:new_line("mod.rs", { on_line = 6, text = "const Z: i32 = 1;", indent = 8 }) + run:new_line("mod.rs", { on_line = 7, text = "const Z: i32 = 1;", indent = 4 }) + run:new_line("string.rs", { on_line = 2, text = "brave new", indent = 0 }) + run:new_line("string.rs", { on_line = 5, text = "brave new \\", indent = 8 }) + run:new_line("string.rs", { on_line = 9, text = "brave new \\", indent = 8 }) + run:new_line("struct.rs", { on_line = 1, text = "z: i32,", indent = 4 }) + run:new_line("struct.rs", { on_line = 2, text = "z: i32,", indent = 4 }) + run:new_line("struct.rs", { on_line = 4, text = "let y = 1;", indent = 0 }) + run:new_line("trait.rs", { on_line = 4, text = "fn baz();", indent = 4 }) + run:new_line("trait.rs", { on_line = 5, text = "let y = 1;", indent = 0 }) + run:new_line("trait.rs", { on_line = 7, text = "fn baz();", indent = 4 }) + run:new_line("trait.rs", { on_line = 8, text = "()", indent = 8 }) + run:new_line("where.rs", { on_line = 17, text = "T: Debug,", indent = 4 }) + run:new_line("where.rs", { on_line = 2, text = "T: Debug,", indent = 4 }) + run:new_line("where.rs", { on_line = 9, text = "T: Debug,", indent = 4 }) end) end) diff --git a/tests/indent/smali/array_and_switch.smali b/tests/indent/smali/array_and_switch.smali deleted file mode 100644 index 3ee3f6d01..000000000 --- a/tests/indent/smali/array_and_switch.smali +++ /dev/null @@ -1,58 +0,0 @@ -.class public Lbaksmali/test/class; -.super Ljava/lang/Object; - -.source "baksmali_test_class.smali" - -.method public testMethod(ILjava/lang/String;)Ljava/lang/String; - .registers 3 - .annotation runtime Lorg/junit/Test; - .end annotation - .annotation system Lyet/another/annotation; - somevalue = 1234 - anothervalue = 3.14159 - .end annotation - - const-string v0, "testing\n123" - - goto switch: - - sget v0, Lbaksmali/test/class;->staticField:I - - switch: - packed-switch v0, pswitch: - - try_start: - const/4 v0, 7 - const v0, 10 - nop - try_end: - .catch Ljava/lang/Exception; {try_start: .. try_end:} handler: - .catchall {try_start: .. try_end:} handler2: - - handler: - - Label10: - Label11: - Label12: - Label13: - return-object v0 - - - - .array-data 4 - 1 2 3 4 5 6 200 - .end array-data - - pswitch: - .packed-switch 10 - Label10: - Label11: - Label12: - Label13: - .end packed-switch - - handler2: - - return-void - -.end method diff --git a/tests/indent/smali/field.smali b/tests/indent/smali/field.smali deleted file mode 100644 index ae48b7b3c..000000000 --- a/tests/indent/smali/field.smali +++ /dev/null @@ -1,12 +0,0 @@ -.class public Lbaksmali/test/class; -.super Ljava/lang/Object; - -.source "baksmali_test_class.smali" - -.field public static annotationStaticField:Lsome/annotation; = .subannotation Lsome/annotation; - value1 = "test" - value2 = .subannotation Lsome/annotation; - value1 = "test2" - value2 = Lsome/enum; - .end subannotation -.end subannotation diff --git a/tests/indent/smali/method.smali b/tests/indent/smali/method.smali deleted file mode 100644 index 2c139b0cb..000000000 --- a/tests/indent/smali/method.smali +++ /dev/null @@ -1,8 +0,0 @@ -.class public Lbaksmali/test/class; -.super Ljava/lang/Object; - -.source "baksmali_test_class.smali" - -.method public debugTest(IIIII)V - .registers 10 -.end method diff --git a/tests/indent/smali/parameter.smali b/tests/indent/smali/parameter.smali deleted file mode 100644 index 2e54da2f9..000000000 --- a/tests/indent/smali/parameter.smali +++ /dev/null @@ -1,55 +0,0 @@ -.class public Lbaksmali/test/class; -.super Ljava/lang/Object; - -.source "baksmali_test_class.smali" - -.method public debugTest(IIIII)V - .registers 10 - - .parameter "Blah" - .parameter - .parameter "BlahWithAnnotations" - .annotation runtime Lsome/annotation; - something = "some value" - somethingelse = 1234 - .end annotation - .annotation runtime La/second/annotation; - .end annotation - .end parameter - .parameter - .annotation runtime Lsome/annotation; - something = "some value" - somethingelse = 1234 - .end annotation - .end parameter - .parameter "LastParam" - - .prologue - - nop - nop - - .source "somefile.java" - .line 101 - - nop - - - .line 50 - - .local v0, aNumber:I - const v0, 1234 - .end local v0 - - .source "someotherfile.java" - .line 900 - - const-string v0, "1234" - - .restart local v0 - const v0, 6789 - .end local v0 - - .epilogue - -.end method diff --git a/tests/indent/smali_spec.lua b/tests/indent/smali_spec.lua deleted file mode 100644 index 44e4a9881..000000000 --- a/tests/indent/smali_spec.lua +++ /dev/null @@ -1,28 +0,0 @@ -local Runner = require('tests.indent.common').Runner - -local run = Runner:new(it, 'tests/indent/smali', { - tabstop = 4, - shiftwidth = 4, - expandtab = false, -}) - -describe('indent Smali:', function() - describe('whole file:', function() - run:whole_file('.', { - expected_failures = {}, - }) - end) - - describe('new line:', function() - run:new_line('field.smali', { on_line = 7, text = 'value1 = "test"', indent = 1 }) - run:new_line('field.smali', { on_line = 10, text = 'value2 = Lsome/enum;', indent = 2 }) - run:new_line('array_and_switch.smali', { on_line = 43, text = '1 2 3 4 5 6 200', indent = 2 }) - run:new_line('array_and_switch.smali', { on_line = 48, text = 'Label10:', indent = 2 }) - run:new_line('method.smali', { on_line = 7, text = '.registers 10', indent = 1 }) - run:new_line( - 'parameter.smali', - { on_line = 20, text = '.annotation runtime Lsome/annotation;', indent = 3 } - ) - run:new_line('parameter.smali', { on_line = 21, text = 'something = "some value"', indent = 3 }) - end) -end) diff --git a/tests/indent/snakemake/blocks.smk b/tests/indent/snakemake/blocks.smk deleted file mode 100644 index fc10e7ae3..000000000 --- a/tests/indent/snakemake/blocks.smk +++ /dev/null @@ -1,22 +0,0 @@ -rule A: - """doc""" - -if True: - rule B: - """doc""" - -use rule other from somewhere - -use rule other2 from somewhere as other_alias - -use rule other3 from somewhere with: - input: 2 - -use rule other4 from somewhere as other_alias2 with: - input: 2 - -checkpoint C: - input: "1" - -module A: - snakefile: "x.smk" diff --git a/tests/indent/snakemake/directive_parameters.smk b/tests/indent/snakemake/directive_parameters.smk deleted file mode 100644 index fa311bfb7..000000000 --- a/tests/indent/snakemake/directive_parameters.smk +++ /dev/null @@ -1,36 +0,0 @@ -rule A: - input: a - output: b - params: - a = 1, - b = 2, - c = 3 - shell: - """ - touch {output} - """ - -rule B: - input: a, - output: a, - b - params: - -rule C: - # test dedent after variably nested nodes - params: - 1 - params: - "1" - params: - a = 1 - params: - a = "1" - params: - a = call(1) - params: - a = call("1") - params: - a = config["a"] - params: - b = call(config["a"]) diff --git a/tests/indent/snakemake_spec.lua b/tests/indent/snakemake_spec.lua deleted file mode 100644 index 111d01113..000000000 --- a/tests/indent/snakemake_spec.lua +++ /dev/null @@ -1,49 +0,0 @@ -local Runner = require('tests.indent.common').Runner -local XFAIL = require('tests.indent.common').XFAIL - -local run = Runner:new(it, 'tests/indent/snakemake', { - tabstop = 4, - shiftwidth = 4, - softtabstop = 0, - expandtab = true, -}) - -describe('indent Snakemake:', function() - describe('whole file:', function() - run:whole_file('.', { - expected_failures = {}, - }) - end) - - describe('new line:', function() - run:new_line('blocks.smk', { on_line = 1, text = 'input: 1', indent = 4 }) - run:new_line('blocks.smk', { on_line = 2, text = 'input: 1', indent = 4 }) - run:new_line('blocks.smk', { on_line = 5, text = 'input: 1', indent = 8 }) - run:new_line('blocks.smk', { on_line = 6, text = 'input: 1', indent = 8 }) - run:new_line('blocks.smk', { on_line = 8, text = 'pass', indent = 0 }) - run:new_line('blocks.smk', { on_line = 10, text = 'pass', indent = 0 }) - run:new_line('blocks.smk', { on_line = 12, text = 'pass', indent = 4 }) - run:new_line('blocks.smk', { on_line = 15, text = 'pass', indent = 4 }) - run:new_line('directive_parameters.smk', { on_line = 4, text = 'before_a = 0,', indent = 8 }) - run:new_line('directive_parameters.smk', { on_line = 5, text = 'after_a = 1.1,', indent = 8 }) - run:new_line( - 'directive_parameters.smk', - { on_line = 7, text = '"""dedent_after_last_param"""', indent = 4 } - ) - run:new_line( - 'directive_parameters.smk', - { on_line = 14, text = 'b = "indent_after_param_with_comma"', indent = 8 } - ) - run:new_line( - 'directive_parameters.smk', - { on_line = 15, text = 'b = "indent_after_param_with_comma"', indent = 8 } - ) - run:new_line( - 'directive_parameters.smk', - { on_line = 17, text = 'b = "indent_after_opening"', indent = 8 } - ) - for _, line in ipairs({ 22, 24, 26, 28, 30, 32, 34, 36 }) do - run:new_line('directive_parameters.smk', { on_line = line, text = '"doc"', indent = 4 }) - end - end) -end) diff --git a/tests/indent/sql/case.sql b/tests/indent/sql/case.sql deleted file mode 100644 index eee85a3be..000000000 --- a/tests/indent/sql/case.sql +++ /dev/null @@ -1,8 +0,0 @@ -select - case - when a = 1 then '1' - when a = 2 then '2' - when a = 3 then '3' - else '0' - end as stmt1 -from tab; diff --git a/tests/indent/sql/compound.sql b/tests/indent/sql/compound.sql deleted file mode 100644 index e645c6efb..000000000 --- a/tests/indent/sql/compound.sql +++ /dev/null @@ -1,3 +0,0 @@ -begin - create table foo (bar int); -end; diff --git a/tests/indent/sql/create.sql b/tests/indent/sql/create.sql deleted file mode 100644 index 977388452..000000000 --- a/tests/indent/sql/create.sql +++ /dev/null @@ -1,4 +0,0 @@ -create table my_table ( - id bigint, - date date -); diff --git a/tests/indent/sql/cte.sql b/tests/indent/sql/cte.sql deleted file mode 100644 index 55426ccc3..000000000 --- a/tests/indent/sql/cte.sql +++ /dev/null @@ -1,7 +0,0 @@ -with data as ( - select - a, - b - from tab -) -select * from data; diff --git a/tests/indent/sql/insert.sql b/tests/indent/sql/insert.sql deleted file mode 100644 index 36fa7c093..000000000 --- a/tests/indent/sql/insert.sql +++ /dev/null @@ -1,5 +0,0 @@ -insert into mytable - (column1, column2) -values - ('john', 123), - ('jane', 124); diff --git a/tests/indent/sql/select.sql b/tests/indent/sql/select.sql deleted file mode 100644 index 85f0cc5b7..000000000 --- a/tests/indent/sql/select.sql +++ /dev/null @@ -1,4 +0,0 @@ -select - a, - b -from tab; diff --git a/tests/indent/sql/subquery.sql b/tests/indent/sql/subquery.sql deleted file mode 100644 index a559d7e5b..000000000 --- a/tests/indent/sql/subquery.sql +++ /dev/null @@ -1,9 +0,0 @@ -select - id -from foo -where id < ( - select - id - from bar - limit 1 -); diff --git a/tests/indent/sql_spec.lua b/tests/indent/sql_spec.lua deleted file mode 100644 index 9d3a3a8e6..000000000 --- a/tests/indent/sql_spec.lua +++ /dev/null @@ -1,19 +0,0 @@ -local Runner = require('tests.indent.common').Runner ---local XFAIL = require("tests.indent.common").XFAIL - -local run = Runner:new(it, 'tests/indent/sql', { - tabstop = 4, - shiftwidth = 4, - softtabstop = 0, - expandtab = true, -}) - -describe('indent SQL:', function() - describe('whole file:', function() - run:whole_file('.', { - expected_failures = {}, - }) - end) - - describe('new line:', function() end) -end) diff --git a/tests/indent/sway/main.sw b/tests/indent/sway/main.sw deleted file mode 100644 index d917895c3..000000000 --- a/tests/indent/sway/main.sw +++ /dev/null @@ -1,345 +0,0 @@ -library; - -use ::alloc::{alloc, realloc}; -use ::assert::assert; -use ::option::Option::{self, *}; -use ::convert::From; -use ::iterator::*; - -struct RawVec { - ptr: raw_ptr, - cap: u64, -} - -pub fn tx_witness_data(index: u64) -> Option { - if index >= tx_witnesses_count() { - return None - } - - let length = match tx_witness_data_length(index) { - Some(len) => len, - None => return None, - }; - - if __is_reference_type::() { - let witness_data_ptr = __gtf::(index, GTF_WITNESS_DATA); - let new_ptr = alloc_bytes(length); - witness_data_ptr.copy_bytes_to(new_ptr, length); - - Some(asm(ptr: new_ptr) { - ptr: T - }) - } else { - // u8 is the only value type that is less than 8 bytes and should be handled separately - if __size_of::() == 1 { - Some(__gtf::(index, GTF_WITNESS_DATA).add::(7).read::()) - } else { - Some(__gtf::(index, GTF_WITNESS_DATA).read::()) - } - } -} - -impl RawVec { - pub fn new() -> Self { - Self { - ptr: alloc::(0), - cap: 0, - } - } - - pub fn with_capacity(capacity: u64) -> Self { - Self { - ptr: alloc::(capacity), - cap: capacity, - } - } - - pub fn ptr(self) -> raw_ptr { - self.ptr - } - - pub fn capacity(self) -> u64 { - self::cap() - } - - pub fn grow(ref mut self) { - let new_cap = if self.cap == 0 { 1 } else { 2 * self.cap }; - - self.ptr = realloc::(self.ptr, self.cap, new_cap); - self.cap = new_cap; - } -} - -impl From for RawVec { - fn from(slice: raw_slice) -> Self { - let cap = slice.len::(); - let ptr = alloc::(cap); - if cap > 0 { - slice.ptr().copy_to::(ptr, cap); - } - Self { ptr, cap } - } -} - -pub struct Vec { - buf: RawVec, - len: u64, -} - -impl Vec { - pub fn new() -> Self { - 'hey: while true { - - } - Self { - buf: RawVec::new(), - len: 0, - } - } - - pub fn with_capacity(capacity: u64) -> Self { - Self { - buf: RawVec::with_capacity(capacity), - len: 0, - } - } - - pub fn push(ref mut self, value: T) { - // If there is insufficient capacity, grow the buffer. - if self.len == self.buf.capacity() { - self.buf.grow(); - }; - - // Get a pointer to the end of the buffer, where the new element will - // be inserted. - let end = self.buf.ptr().add::(self.len); - - // Write `value` at pointer `end` - end.write::(value); - - // Increment length. - self.len += 1; - } - - pub fn capacity(self) -> u64 { - self.buf.capacity() - } - - pub fn clear(ref mut self) { - self.len = 0; - } - - pub fn get(self, index: u64) -> Option { - // First check that index is within bounds. - if self.len <= index { - return None; - }; - - // Get a pointer to the desired element using `index` - let ptr = self.buf.ptr().add::(index); - - // Read from `ptr` - Some(ptr.read::()) - } - - pub fn len(self) -> u64 { - self.len - } - - pub fn is_empty(self) -> bool { - self.len == 0 - } - - pub fn remove(ref mut self, index: u64) -> T { - assert(index < self.len); - - let buf_start = self.buf.ptr(); - - // Read the value at `index` - let ptr = buf_start.add::(index); - let ret = ptr.read::(); - - // Shift everything down to fill in that spot. - let mut i = index; - if self.len > 1 { - while i < self.len - 1 { - let ptr = buf_start.add::(i); - ptr.add::(1).copy_to::(ptr, 1); - i += 1; - } - } - - // Decrease length. - self.len -= 1; - ret - } - - pub fn insert(ref mut self, index: u64, element: T) { - assert(index <= self.len); - - // If there is insufficient capacity, grow the buffer. - if self.len == self.buf.capacity() { - self.buf.grow(); - } - - let buf_start = self.buf.ptr(); - - // The spot to put the new value - let index_ptr = buf_start.add::(index); - - // Shift everything over to make space. - let mut i = self.len; - while i > index { - let ptr = buf_start.add::(i); - ptr.sub::(1).copy_to::(ptr, 1); - i -= 1; - } - - // Write `element` at pointer `index` - index_ptr.write::(element); - - // Increment length. - self.len += 1; - } - - pub fn pop(ref mut self) -> Option { - if self.len == 0 { - return None; - } - self.len -= 1; - Some(self.buf.ptr().add::(self.len).read::()) - } - - pub fn swap(ref mut self, element1_index: u64, element2_index: u64) { - assert(element1_index < self.len); - assert(element2_index < self.len); - - if element1_index == element2_index { - return; - } - - let element1_ptr = self.buf.ptr().add::(element1_index); - let element2_ptr = self.buf.ptr().add::(element2_index); - - let element1_val: T = element1_ptr.read::(); - element2_ptr.copy_to::(element1_ptr, 1); - element2_ptr.write::(element1_val); - } - - pub fn set(ref mut self, index: u64, value: T) { - assert(index < self.len); - - let index_ptr = self.buf.ptr().add::(index); - - index_ptr.write::(value); - } - - pub fn iter(self) -> VecIter { - VecIter { - values: self, - index: 0, - } - } - - pub fn ptr(self) -> raw_ptr { - self.buf.ptr() - } -} - -impl AsRawSlice for Vec { - fn as_raw_slice(self) -> raw_slice { - raw_slice::from_parts::(self.buf.ptr(), self.len) - } -} - -impl From for Vec { - fn from(slice: raw_slice) -> Self { - Self { - buf: RawVec::from(slice), - len: slice.len::(), - } - } -} - -impl From> for raw_slice { - fn from(vec: Vec) -> Self { - asm(ptr: (vec.ptr(), vec.len())) { - ptr: raw_slice - } - } - - pub fn sha256(self) -> b256 { - let mut result_buffer = b256::min(); - asm( - hash: result_buffer, - ptr: p, - bytes: p, - ) { - s256 hash ptr bytes; - hash: b256 - } - } -} - -impl AbiEncode for Vec -where - T: AbiEncode, -{ - fn abi_encode(self, buffer: Buffer) -> Buffer { - let len = self.len(); - let mut buffer = len.abi_encode(buffer); - - let mut i = 0; - while i < len { - let item = self.get(i).unwrap(); - buffer = item.abi_encode(buffer); - i += 1; - } - - buffer - } -} - -impl AbiDecode for Vec -where - T: AbiDecode, -{ - fn abi_decode(ref buffer: BufferReader) -> Vec { - let len = u64::abi_decode(buffer); - - let mut v = Vec::with_capacity(len); - - let mut i = 0; - while i < len { - let item = T::abi_decode(buffer); - v.push(item); - i += 1; - } - - yield 5; - - v - } -} - -pub struct VecIter { - values: Vec, - index: u64, -} - -impl Iterator for VecIter { - type Item = T; - fn next(ref mut self) -> Option { - if self.index >= self.values.len()? { - return None - } - - self.index += 1; - self.values.get(self.index - 1) - } -} - -fn hello(hi: T) { - println("{}", hi); -} -// vim: ft=sway diff --git a/tests/indent/sway_spec.lua b/tests/indent/sway_spec.lua deleted file mode 100644 index d6f4506ef..000000000 --- a/tests/indent/sway_spec.lua +++ /dev/null @@ -1,20 +0,0 @@ -local Runner = require('tests.indent.common').Runner - -local run = Runner:new(it, 'tests/indent/sway', { - tabstop = 4, - shiftwidth = 4, - softtabstop = 4, - expandtab = true, -}) - -describe('indent Sway:', function() - describe('whole file:', function() - run:whole_file('.', {}) - end) - describe('new line:', function() - run:new_line('main.sw', { on_line = 12, text = 'const CONST: u32 = 2;', indent = 0 }) - run:new_line('main.sw', { on_line = 14, text = 'let hi = 5;', indent = 4 }) - run:new_line('main.sw', { on_line = 15, text = 'let hi = 5;', indent = 8 }) - run:new_line('main.sw', { on_line = 92, text = 'let hi = 5;', indent = 12 }) - end) -end) diff --git a/tests/indent/swift/declarations.swift b/tests/indent/swift/declarations.swift deleted file mode 100644 index 67a7e5544..000000000 --- a/tests/indent/swift/declarations.swift +++ /dev/null @@ -1,56 +0,0 @@ -@wrapper -@modifier( - * -) -class EquilateralTriangle: NamedShape { - var sideLength: Double = 0.0 - - @attr - init( - sideLength: Double, - name: String - ) { - self.sideLength = sideLength - } - deinit { - } - - var perimeter: Double { - willSet { - } - didSet { - - } - } - - @funcattr - override func simpleDescription(a: int, b: int) -> String { - return "An equilateral triangle with sides of length \(sideLength)." - } -} - -@attr -protocol ExampleProtocol { - var simpleDescription: String { get } - mutating func adjust() -} - -@available(*) -func test() { - -} - -@attr(*) -typealias Foo = Bar - -@attr -struct Foo< - Bar -> { - @Provider - var test = 1 - - subscript(index: Int) -> Int { - var foo = 2 - } -} diff --git a/tests/indent/swift/expressions.swift b/tests/indent/swift/expressions.swift deleted file mode 100644 index 4f7292a69..000000000 --- a/tests/indent/swift/expressions.swift +++ /dev/null @@ -1,17 +0,0 @@ -func Test() { - (1 + 2) - - [ - 1, - 2, - 3, - 4, - 5 - ].split() - - let x = [ - 1: 2, - 3: 4, - ] - -} diff --git a/tests/indent/swift/statements.swift b/tests/indent/swift/statements.swift deleted file mode 100644 index df6e46c94..000000000 --- a/tests/indent/swift/statements.swift +++ /dev/null @@ -1,34 +0,0 @@ -func Test() { - if true { - return - } else if true { - return - } - - switch x { - case "1": - print("x") - default: - print("y") - @unknown default: - print("z") - } - - for a in b { - } - - while true{ - } - - repeat { - - } while (true) - - guard let name = person["name"] else { - return - } - - return ( - x + 1 - ) -} diff --git a/tests/indent/swift_spec.lua b/tests/indent/swift_spec.lua deleted file mode 100644 index 8c9b2d063..000000000 --- a/tests/indent/swift_spec.lua +++ /dev/null @@ -1,37 +0,0 @@ -local Runner = require('tests.indent.common').Runner - -local run = Runner:new(it, 'tests/indent/swift', { - tabstop = 2, - shiftwidth = 2, - softtabstop = 2, - expandtab = true, -}) - -describe('indent Swift:', function() - describe('whole file:', function() - run:whole_file('.', {}) - end) - describe('new line:', function() - run:new_line('declarations.swift', { on_line = 6, text = 'var x = 1', indent = 2 }) - run:new_line( - 'declarations.swift', - { on_line = 12, text = 'var textInsideInit = true', indent = 4 } - ) - run:new_line( - 'declarations.swift', - { on_line = 19, text = 'var textInsideWillSet = 1', indent = 6 } - ) - run:new_line( - 'declarations.swift', - { on_line = 22, text = 'var textInsideDidSet = 1', indent = 6 } - ) - run:new_line( - 'declarations.swift', - { on_line = 27, text = 'var textInsideOverrideFunc', indent = 4 } - ) - run:new_line( - 'declarations.swift', - { on_line = 33, text = 'var InsideProtocol: String { get }', indent = 2 } - ) - end) -end) diff --git a/tests/indent/t32/if_block.cmm b/tests/indent/t32/if_block.cmm deleted file mode 100644 index 4bda7c6e5..000000000 --- a/tests/indent/t32/if_block.cmm +++ /dev/null @@ -1,49 +0,0 @@ -IF &a - STOP - -IF (TRUE()) -( - BREAK -) - -IF (&b+CouNT()) -( - continue -) - -IF FOUND() - STOP -ELSE - CONTinue - -IF &c - CONTinue -ELSE IF FALSE() - Break -ELSE - stop - -IF &d -( - STOP -) -ELSE IF &e -; comment A -( - CONTINUE -) -ELSE -; comment B -( - BREAK -) - -IF &f - IF &g - stop - ELSE - IF &h - ( - continue - ) - diff --git a/tests/indent/t32/repeat_block.cmm b/tests/indent/t32/repeat_block.cmm deleted file mode 100644 index 6384183dc..000000000 --- a/tests/indent/t32/repeat_block.cmm +++ /dev/null @@ -1,27 +0,0 @@ -RePeaT 10. PRINT "A" - -RePeaT &a - print - -REPEAT 0xaAfF09 -( - cont -) - -RPT -( - b -) - -rpt -( - s -) -WHILE &a - -REPEAT TRUE() -; comment -( - cont -) - diff --git a/tests/indent/t32/subroutine_block.cmm b/tests/indent/t32/subroutine_block.cmm deleted file mode 100644 index 24891c609..000000000 --- a/tests/indent/t32/subroutine_block.cmm +++ /dev/null @@ -1,23 +0,0 @@ -printA: -( - PRINT "A" - RETURN -) - -sUBROUtINE printB -( - ENTRY &in - - PRINT "&in" - RETURN -) - -SUBROUTINE printC -// comment -( - PARAMETERS &a &b - - PRINT "&a"+"&b" - ENDDO -) - diff --git a/tests/indent/t32/while_block.cmm b/tests/indent/t32/while_block.cmm deleted file mode 100644 index bfcbd45db..000000000 --- a/tests/indent/t32/while_block.cmm +++ /dev/null @@ -1,14 +0,0 @@ -WHILE &a - Step - -WHILE (sYmbol.EXIT(main)) -( - Step - Break -) - -WHILE (FALSE()) -// comment -( - ECHO "test" -) diff --git a/tests/indent/t32_spec.lua b/tests/indent/t32_spec.lua deleted file mode 100644 index 30c6542e0..000000000 --- a/tests/indent/t32_spec.lua +++ /dev/null @@ -1,172 +0,0 @@ -local Runner = require('tests.indent.common').Runner -local XFAIL = require('tests.indent.common').XFAIL - -local runner = Runner:new(it, 'tests/indent/t32', { - tabstop = 2, - shiftwidth = 2, - softtabstop = 0, - expandtab = true, -}) - -describe('indent t32:', function() - describe('whole file:', function() - runner:whole_file('.') - end) - - describe('new line:', function() - runner:new_line( - 'if_block.cmm', - { on_line = 2, text = 'GOTO start', indent = 0 }, - 'command after IF', - XFAIL - ) - - runner:new_line( - 'if_block.cmm', - { on_line = 5, text = 'GOTO start', indent = 2 }, - 'command in IF then block' - ) - - runner:new_line('if_block.cmm', { on_line = 4, text = '(', indent = 0 }, 'block after IF') - - for ii, test in ipairs({ - { 1, 2 }, - { 14, 2 }, - { 19, 2 }, - { 21, 2 }, - { 41, 2 }, - { 42, 4 }, - }) do - runner:new_line( - 'if_block.cmm', - { on_line = test[1], text = '&x=1.', indent = test[2] }, - 'command in IF then[' .. ii .. ']' - ) - end - - -- Insertion of a command right before the existing block results in - -- incorrect syntax. The parse either detect an error or incorrectly - -- assumes "ELSE IF" is a command. - for ii, test in ipairs({ - { 26, 2 }, - { 30, 2 }, - }) do - runner:new_line( - 'if_block.cmm', - { on_line = test[1], text = 'PRINT ""', indent = test[2] }, - 'displace block in IF then[' .. ii .. ']', - XFAIL - ) - end - - runner:new_line( - 'if_block.cmm', - { on_line = 45, text = '&x=1.', indent = 6 }, - 'command in IF then', - XFAIL - ) - - for ii, test in ipairs({ - { 16, 2 }, - { 21, 2 }, - { 23, 2 }, - { 44, 4 }, - }) do - runner:new_line( - 'if_block.cmm', - { on_line = test[1], text = 'CONTinue\n', indent = test[2] }, - 'command in IF else[' .. ii .. ']' - ) - end - - runner:new_line( - 'while_block.cmm', - { on_line = 2, text = '&x=1.', indent = 2 }, - 'command after WHILE' - ) - - runner:new_line( - 'while_block.cmm', - { on_line = 4, text = '&x=1.', indent = 0 }, - 'command after WHILE' - ) - - runner:new_line( - 'while_block.cmm', - { on_line = 1, text = '(\n', indent = 0 }, - 'block in WHILE then' - ) - - for ii, test in ipairs({ - { 5, 2 }, - { 12, 2 }, - }) do - runner:new_line( - 'while_block.cmm', - { on_line = test[1], text = '&x=1.', indent = test[2] }, - 'command in WHILE then block[' .. ii .. ']' - ) - end - - for ii, test in ipairs({ - { 1, 0 }, - { 4, 2 }, - }) do - runner:new_line( - 'repeat_block.cmm', - { on_line = test[1], text = '&x=1.', indent = test[2] }, - 'command after RePeaT[' .. ii .. ']' - ) - end - - runner:new_line( - 'repeat_block.cmm', - { on_line = 3, text = '(\n', indent = 0 }, - 'block in RePeaT then' - ) - - for ii, test in ipairs({ - { 7, 2 }, - { 18, 2 }, - { 24, 2 }, - }) do - runner:new_line( - 'repeat_block.cmm', - { on_line = test[1], text = '&x=1.', indent = test[2] }, - 'command in RePeaT then block [' .. ii .. ']' - ) - end - - runner:new_line( - 'subroutine_block.cmm', - { on_line = 1, text = '(\n', indent = 0 }, - 'block after call label' - ) - - for ii, test in ipairs({ - { 2, 2 }, - { 3, 2 }, - { 8, 2 }, - { 12, 2 }, - { 19, 2 }, - }) do - runner:new_line( - 'subroutine_block.cmm', - { on_line = test[1], text = '&x=1.', indent = test[2] }, - 'command in subroutine block[' .. ii .. ']' - ) - end - - for ii, test in ipairs({ - { 5, 2 }, - { 13, 2 }, - { 23, 2 }, - }) do - runner:new_line( - 'subroutine_block.cmm', - { on_line = test[1], text = '&x=1.', indent = test[2] }, - 'command after subroutine block[' .. ii .. ']' - ) - end - end) -end) diff --git a/tests/indent/terraform_spec.lua b/tests/indent/terraform_spec.lua deleted file mode 100644 index 3cfcb937b..000000000 --- a/tests/indent/terraform_spec.lua +++ /dev/null @@ -1,56 +0,0 @@ -local Runner = require('tests.indent.common').Runner ---local XFAIL = require("tests.indent.common").XFAIL - -local run = Runner:new(it, 'tests/indent/terraform', { - tabstop = 2, - shiftwidth = 2, - expandtab = true, -}) - -describe('indent Terraform:', function() - describe('whole file:', function() - run:whole_file('.', { - expected_failures = {}, - }) - end) - - describe('new line:', function() - run:new_line( - 'no-indent-after-brace.tf', - { on_line = 4, text = '# Wow, no indent here please', indent = 0 } - ) - run:new_line('indent-in-multiline-tuples.tf', { on_line = 4, text = '3,', indent = 4 }) - run:new_line( - 'indent-in-multiline-tuples.tf', - { on_line = 3, text = '# as elements', indent = 4 } - ) - run:new_line( - 'indent-in-multiline-tuples.tf', - { on_line = 5, text = '# as outer block', indent = 2 } - ) - run:new_line( - 'indent-in-multiline-tuples.tf', - { on_line = 1, text = '# as outer block', indent = 2 } - ) - run:new_line('indent-in-multiline-objects.tf', { on_line = 4, text = '3: "baz",', indent = 4 }) - run:new_line( - 'indent-in-multiline-objects.tf', - { on_line = 3, text = '# as elements', indent = 4 } - ) - run:new_line( - 'indent-in-multiline-objects.tf', - { on_line = 5, text = '# as outer block', indent = 2 } - ) - run:new_line( - 'indent-in-multiline-objects.tf', - { on_line = 1, text = '# as outer block', indent = 2 } - ) - run:new_line('multiple-attributes.tf', { on_line = 2, text = 'a = 1', indent = 2 }) - run:new_line('multiple-attributes.tf', { on_line = 3, text = 'a = 1', indent = 2 }) - run:new_line('multiple-attributes.tf', { on_line = 4, text = 'a = 1', indent = 0 }) - run:new_line('nested_blocks.tf', { on_line = 3, text = 'a = 1', indent = 4 }) - run:new_line('nested_blocks.tf', { on_line = 4, text = 'a = 1', indent = 2 }) - run:new_line('function_call.tf', { on_line = 4, text = 'c,', indent = 4 }) - run:new_line('function_call.tf', { on_line = 5, text = 'a = 1', indent = 2 }) - end) -end) diff --git a/tests/indent/tiger_spec.lua b/tests/indent/tiger_spec.lua index b41019c12..f435b4c03 100644 --- a/tests/indent/tiger_spec.lua +++ b/tests/indent/tiger_spec.lua @@ -1,233 +1,138 @@ -local Runner = require('tests.indent.common').Runner +local Runner = require("tests.indent.common").Runner +local XFAIL = require("tests.indent.common").XFAIL -local runner = Runner:new(it, 'tests/indent/tiger', { +local runner = Runner:new(it, "tests/indent/tiger", { tabstop = 2, shiftwidth = 2, softtabstop = 0, expandtab = true, }) -describe('indent Tiger:', function() - describe('whole file:', function() - runner:whole_file('.') +describe("indent Tiger:", function() + describe("whole file:", function() + runner:whole_file "." end) - describe('new line:', function() + describe("new line:", function() runner:new_line( - 'classes.tig', - { on_line = 1, text = 'var a := 0', indent = 2 }, - 'class declaration beginning' - ) - runner:new_line( - 'classes.tig', - { on_line = 2, text = 'var a := 0', indent = 2 }, - 'class declaration after field' - ) - runner:new_line( - 'classes.tig', - { on_line = 4, text = 'var a := 0', indent = 2 }, - 'class declaration after method' - ) - runner:new_line( - 'classes.tig', - { on_line = 5, text = 'var a := 0', indent = 0 }, - 'after class declaration' - ) - runner:new_line( - 'classes.tig', - { on_line = 7, text = 'var a := 0', indent = 2 }, - 'class type beginning' - ) - runner:new_line( - 'classes.tig', - { on_line = 8, text = 'var a := 0', indent = 2 }, - 'class type after field' - ) - runner:new_line( - 'classes.tig', - { on_line = 10, text = 'self.a := 0', indent = 4 }, - 'inside method' - ) - runner:new_line( - 'classes.tig', - { on_line = 13, text = 'var a := 0', indent = 2 }, - 'class type after method' - ) - runner:new_line( - 'classes.tig', - { on_line = 14, text = 'var a := 0', indent = 0 }, - 'after class type' + "classes.tig", + { on_line = 1, text = "var a := 0", indent = 2 }, + "class declaration beginning", + XFAIL ) + runner:new_line("classes.tig", { on_line = 2, text = "var a := 0", indent = 2 }, "class declaration after field") + runner:new_line("classes.tig", { on_line = 4, text = "var a := 0", indent = 2 }, "class declaration after method") + runner:new_line("classes.tig", { on_line = 5, text = "var a := 0", indent = 0 }, "after class declaration") + runner:new_line("classes.tig", { on_line = 7, text = "var a := 0", indent = 2 }, "class type beginning", XFAIL) + runner:new_line("classes.tig", { on_line = 8, text = "var a := 0", indent = 2 }, "class type after field") + runner:new_line("classes.tig", { on_line = 10, text = "self.a := 0", indent = 4 }, "inside method", XFAIL) + runner:new_line("classes.tig", { on_line = 13, text = "var a := 0", indent = 2 }, "class type after method") + runner:new_line("classes.tig", { on_line = 14, text = "var a := 0", indent = 0 }, "after class type") - runner:new_line('control-flow.tig', { on_line = 2, text = 'true', indent = 4 }, 'if condition') - runner:new_line( - 'control-flow.tig', - { on_line = 4, text = 'true', indent = 4 }, - 'if consequence' - ) - runner:new_line( - 'control-flow.tig', - { on_line = 4, text = 'true', indent = 4 }, - 'if alternative' - ) - runner:new_line( - 'control-flow.tig', - { on_line = 10, text = 'start := 0', indent = 4 }, - 'for index start' - ) - runner:new_line( - 'control-flow.tig', - { on_line = 12, text = 'the_end', indent = 4 }, - 'for index end' - ) - runner:new_line('control-flow.tig', { on_line = 14, text = 'break', indent = 4 }, 'for body') - runner:new_line( - 'control-flow.tig', - { on_line = 18, text = 'true', indent = 4 }, - 'while condition' - ) - runner:new_line('control-flow.tig', { on_line = 20, text = 'break', indent = 4 }, 'while body') + runner:new_line("control-flow.tig", { on_line = 2, text = "true", indent = 4 }, "if condition", XFAIL) + runner:new_line("control-flow.tig", { on_line = 4, text = "true", indent = 4 }, "if consequence", XFAIL) + runner:new_line("control-flow.tig", { on_line = 4, text = "true", indent = 4 }, "if alternative", XFAIL) + runner:new_line("control-flow.tig", { on_line = 10, text = "start := 0", indent = 4 }, "for index start", XFAIL) + runner:new_line("control-flow.tig", { on_line = 12, text = "the_end", indent = 4 }, "for index end", XFAIL) + runner:new_line("control-flow.tig", { on_line = 14, text = "break", indent = 4 }, "for body", XFAIL) + runner:new_line("control-flow.tig", { on_line = 18, text = "true", indent = 4 }, "while condition", XFAIL) + runner:new_line("control-flow.tig", { on_line = 20, text = "break", indent = 4 }, "while body", XFAIL) runner:new_line( - 'functions.tig', - { on_line = 1, text = 'parameter: int,', indent = 2 }, - 'parameter list beginning' + "functions.tig", + { on_line = 1, text = "parameter: int,", indent = 2 }, + "parameter list beginning", + XFAIL ) + runner:new_line("functions.tig", { on_line = 2, text = "parameter: int,", indent = 2 }, "parameter list middle") + runner:new_line("functions.tig", { on_line = 4, text = ",parameter: int", indent = 2 }, "parameter list end") + runner:new_line("functions.tig", { on_line = 5, text = "var a := 0", indent = 0 }, "after parameter list") + runner:new_line("functions.tig", { on_line = 7, text = "print(a)", indent = 2 }, "function body", XFAIL) + runner:new_line("functions.tig", { on_line = 9, text = "a,", indent = 6 }, "function call beginning", XFAIL) + runner:new_line("functions.tig", { on_line = 10, text = "a,", indent = 6 }, "function call middle") + runner:new_line("functions.tig", { on_line = 12, text = ",a", indent = 6 }, "function call end") + runner:new_line("functions.tig", { on_line = 13, text = "; print(a)", indent = 4 }, "after function call") runner:new_line( - 'functions.tig', - { on_line = 2, text = 'parameter: int,', indent = 2 }, - 'parameter list middle' - ) - runner:new_line( - 'functions.tig', - { on_line = 4, text = ',parameter: int', indent = 2 }, - 'parameter list end' - ) - runner:new_line( - 'functions.tig', - { on_line = 5, text = 'var a := 0', indent = 0 }, - 'after parameter list' - ) - runner:new_line( - 'functions.tig', - { on_line = 7, text = 'print(a)', indent = 2 }, - 'function body' - ) - runner:new_line( - 'functions.tig', - { on_line = 9, text = 'a,', indent = 6 }, - 'function call beginning' - ) - runner:new_line( - 'functions.tig', - { on_line = 10, text = 'a,', indent = 6 }, - 'function call middle' - ) - runner:new_line('functions.tig', { on_line = 12, text = ',a', indent = 6 }, 'function call end') - runner:new_line( - 'functions.tig', - { on_line = 13, text = '; print(a)', indent = 4 }, - 'after function call' - ) - runner:new_line( - 'functions.tig', - { on_line = 14, text = 'var a := 12', indent = 0 }, - 'after function declaration' + "functions.tig", + { on_line = 14, text = "var a := 12", indent = 0 }, + "after function declaration", + XFAIL ) - runner:new_line( - 'groupings.tig', - { on_line = 2, text = 'var b := 0', indent = 2 }, - 'let declarations' - ) - runner:new_line('groupings.tig', { on_line = 3, text = 'a := a + 1', indent = 2 }, "after 'in'") - runner:new_line('groupings.tig', { on_line = 4, text = 'a := a + 1;', indent = 4 }, 'sequence') - runner:new_line( - 'groupings.tig', - { on_line = 8, text = 'a := a + 1;', indent = 2 }, - 'after sequence' - ) - runner:new_line('groupings.tig', { on_line = 10, text = '+ 1', indent = 0 }, "after 'end'") + runner:new_line("groupings.tig", { on_line = 2, text = "var b := 0", indent = 2 }, "let declarations") + runner:new_line("groupings.tig", { on_line = 3, text = "a := a + 1", indent = 2 }, "after 'in'", XFAIL) + runner:new_line("groupings.tig", { on_line = 4, text = "a := a + 1;", indent = 4 }, "sequence", XFAIL) + runner:new_line("groupings.tig", { on_line = 8, text = "a := a + 1;", indent = 2 }, "after sequence") + runner:new_line("groupings.tig", { on_line = 10, text = "+ 1", indent = 0 }, "after 'end'") runner:new_line( - 'values-and-expressions.tig', - { on_line = 4, text = 'field: record,', indent = 4 }, - 'record type beginning' + "values-and-expressions.tig", + { on_line = 4, text = "field: record,", indent = 4 }, + "record type beginning", + XFAIL ) runner:new_line( - 'values-and-expressions.tig', - { on_line = 5, text = 'field: record,', indent = 4 }, - 'record type middle' + "values-and-expressions.tig", + { on_line = 5, text = "field: record,", indent = 4 }, + "record type middle" ) runner:new_line( - 'values-and-expressions.tig', - { on_line = 7, text = ',field: record', indent = 4 }, - 'record type end' + "values-and-expressions.tig", + { on_line = 7, text = ",field: record", indent = 4 }, + "record type end" + ) + runner:new_line("values-and-expressions.tig", { on_line = 8, text = "var a := 0", indent = 2 }, "after record type") + runner:new_line( + "values-and-expressions.tig", + { on_line = 10, text = "0", indent = 4 }, + "variable declaration init value", + XFAIL ) runner:new_line( - 'values-and-expressions.tig', - { on_line = 8, text = 'var a := 0', indent = 2 }, - 'after record type' + "values-and-expressions.tig", + { on_line = 11, text = "+ a", indent = 4 }, + "variable declaration init follow-up" + ) + runner:new_line("values-and-expressions.tig", { on_line = 13, text = "a", indent = 4 }, "array index", XFAIL) + runner:new_line("values-and-expressions.tig", { on_line = 14, text = "+ a", indent = 4 }, "array index follow-up") + runner:new_line("values-and-expressions.tig", { on_line = 15, text = "+ a", indent = 2 }, "after array value") + runner:new_line( + "values-and-expressions.tig", + { on_line = 18, text = "a", indent = 4 }, + "array expression size", + XFAIL ) runner:new_line( - 'values-and-expressions.tig', - { on_line = 10, text = '0', indent = 4 }, - 'variable declaration init value' + "values-and-expressions.tig", + { on_line = 20, text = "of", indent = 2 }, + "array expression after size" ) runner:new_line( - 'values-and-expressions.tig', - { on_line = 11, text = '+ a', indent = 4 }, - 'variable declaration init follow-up' + "values-and-expressions.tig", + { on_line = 21, text = "a", indent = 4 }, + "array expression init value", + XFAIL ) runner:new_line( - 'values-and-expressions.tig', - { on_line = 13, text = 'a', indent = 4 }, - 'array index' + "values-and-expressions.tig", + { on_line = 25, text = "field = 0,", indent = 4 }, + "record expression beginning", + XFAIL ) runner:new_line( - 'values-and-expressions.tig', - { on_line = 14, text = '+ a', indent = 4 }, - 'array index follow-up' + "values-and-expressions.tig", + { on_line = 26, text = "field = 0,", indent = 4 }, + "record expression middle" ) runner:new_line( - 'values-and-expressions.tig', - { on_line = 15, text = '+ a', indent = 2 }, - 'after array value' + "values-and-expressions.tig", + { on_line = 28, text = ",field = 0", indent = 4 }, + "record expression end" ) runner:new_line( - 'values-and-expressions.tig', - { on_line = 18, text = 'a', indent = 4 }, - 'array expression size' - ) - runner:new_line( - 'values-and-expressions.tig', - { on_line = 20, text = 'of', indent = 4 }, - 'array expression after size' - ) - runner:new_line( - 'values-and-expressions.tig', - { on_line = 21, text = 'a', indent = 4 }, - 'array expression init value' - ) - runner:new_line( - 'values-and-expressions.tig', - { on_line = 25, text = 'field = 0,', indent = 4 }, - 'record expression beginning' - ) - runner:new_line( - 'values-and-expressions.tig', - { on_line = 26, text = 'field = 0,', indent = 4 }, - 'record expression middle' - ) - runner:new_line( - 'values-and-expressions.tig', - { on_line = 28, text = ',field = 0', indent = 4 }, - 'record expression end' - ) - runner:new_line( - 'values-and-expressions.tig', - { on_line = 29, text = 'a := 0', indent = 2 }, - 'after record expression' + "values-and-expressions.tig", + { on_line = 29, text = "a := 0", indent = 2 }, + "after record expression" ) end) end) diff --git a/tests/indent/typst/call.typ b/tests/indent/typst/call.typ deleted file mode 100644 index f0a64c97a..000000000 --- a/tests/indent/typst/call.typ +++ /dev/null @@ -1,14 +0,0 @@ -#foo( - arg1, - arg2, -) - -#bar[ - content here -] - -#baz( - inner( - nested, - ), -) diff --git a/tests/indent/typst/for.typ b/tests/indent/typst/for.typ deleted file mode 100644 index 95fe60e9a..000000000 --- a/tests/indent/typst/for.typ +++ /dev/null @@ -1,8 +0,0 @@ -#for x in (1, 2, 3) { - x -} - -#for x in (1, 2, 3) { - let y = x + 1 - y -} diff --git a/tests/indent/typst/if.typ b/tests/indent/typst/if.typ deleted file mode 100644 index 41bbaa4c1..000000000 --- a/tests/indent/typst/if.typ +++ /dev/null @@ -1,15 +0,0 @@ -#if true { - "this is one leve" -} - -#set page(header: { - if true { - "this is internal on level" - } -}) - -#if true { - if false { - "this is it" - } -} diff --git a/tests/indent/typst/let.typ b/tests/indent/typst/let.typ deleted file mode 100644 index fa0c374c6..000000000 --- a/tests/indent/typst/let.typ +++ /dev/null @@ -1,13 +0,0 @@ -#let foo( - x, - y, -) = x + y - -#let bar = { - let x = 1 - x -} - -#let baz(x) = { - x + 1 -} diff --git a/tests/indent/typst/set.typ b/tests/indent/typst/set.typ deleted file mode 100644 index 861b2f95e..000000000 --- a/tests/indent/typst/set.typ +++ /dev/null @@ -1,9 +0,0 @@ -#set text( - size: 12pt, - font: "Arial", -) - -#set page( - width: 210mm, - height: 297mm, -) diff --git a/tests/indent/typst/show.typ b/tests/indent/typst/show.typ deleted file mode 100644 index 3947b66c6..000000000 --- a/tests/indent/typst/show.typ +++ /dev/null @@ -1,7 +0,0 @@ -#show heading: it => { - it -} - -#show link: it => { - underline(it) -} diff --git a/tests/indent/typst_spec.lua b/tests/indent/typst_spec.lua deleted file mode 100644 index 81540405f..000000000 --- a/tests/indent/typst_spec.lua +++ /dev/null @@ -1,12 +0,0 @@ -local Runner = require('tests.indent.common').Runner - -local run = Runner:new(it, 'tests/indent/typst', { - tabstop = 4, - shiftwidth = 4, - softtabstop = 4, - expandtab = false, -}) - -describe('indent typst:', function() - run:whole_file('.') -end) diff --git a/tests/indent/usd/prim.usd b/tests/indent/usd/prim.usd deleted file mode 100644 index 4bfbff955..000000000 --- a/tests/indent/usd/prim.usd +++ /dev/null @@ -1,6 +0,0 @@ -#usda 1.0 - -def "foo" ( -) -{ -} diff --git a/tests/indent/usd_spec.lua b/tests/indent/usd_spec.lua deleted file mode 100644 index 85e9b9f78..000000000 --- a/tests/indent/usd_spec.lua +++ /dev/null @@ -1,21 +0,0 @@ -local Runner = require('tests.indent.common').Runner - -local run = Runner:new(it, 'tests/indent/usd', { - tabstop = 4, - shiftwidth = 4, - softtabstop = 4, - expandtab = true, -}) - -describe('indent USD:', function() - describe('whole file:', function() - run:whole_file('.', { - expected_failures = {}, - }) - end) - - describe('new line:', function() - run:new_line('prim.usd', { on_line = 3, text = 'active = false', indent = 4 }) - run:new_line('prim.usd', { on_line = 5, text = 'custom int foo = 10', indent = 4 }) - end) -end) diff --git a/tests/indent/vue/template_indent.vue b/tests/indent/vue/template_indent.vue deleted file mode 100644 index 95d891f84..000000000 --- a/tests/indent/vue/template_indent.vue +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/tests/indent/vue_spec.lua b/tests/indent/vue_spec.lua deleted file mode 100644 index ec9466d5e..000000000 --- a/tests/indent/vue_spec.lua +++ /dev/null @@ -1,29 +0,0 @@ -local Runner = require('tests.indent.common').Runner --- local XFAIL = require("tests.indent.common").XFAIL - -local run = Runner:new(it, 'tests/indent', { - tabstop = 2, - shiftwidth = 2, - softtabstop = 0, - expandtab = true, -}) - -describe('indent Vue:', function() - describe('whole file:', function() - run:whole_file({ 'vue/' }, {}) - end) - - describe('new line:', function() - for _, info in ipairs({ - { 1, 2 }, - { 3, 0 }, - }) do - run:new_line( - 'vue/template_indent.vue', - { on_line = info[1], text = 'Foo', indent = info[2] }, - info[3], - info[4] - ) - end - end) -end) diff --git a/tests/indent/wgsl/basic.wgsl b/tests/indent/wgsl/basic.wgsl index ccf29a360..7dd50f87e 100644 --- a/tests/indent/wgsl/basic.wgsl +++ b/tests/indent/wgsl/basic.wgsl @@ -41,20 +41,3 @@ fn vertex(vertex: Vertex, out.b = 2; return out; } - -fn foo( - a: u32, - b: u32, -) { - return a; -} - -fn bar( -) {} - -fn baz( - a: u32, -) {} - -fn qux( -) diff --git a/tests/indent/wgsl/type_constructor_or_function_call_expression.wgsl b/tests/indent/wgsl/type_constructor_or_function_call_expression.wgsl deleted file mode 100644 index dff667e77..000000000 --- a/tests/indent/wgsl/type_constructor_or_function_call_expression.wgsl +++ /dev/null @@ -1,11 +0,0 @@ -fn f() { - let a = foo( - b, - c, - ); - - let a = Foo( - b, - c, - ); -} diff --git a/tests/indent/wgsl_spec.lua b/tests/indent/wgsl_spec.lua index 9a30cff4b..4ffdbbda0 100644 --- a/tests/indent/wgsl_spec.lua +++ b/tests/indent/wgsl_spec.lua @@ -1,44 +1,19 @@ -local Runner = require('tests.indent.common').Runner +local Runner = require("tests.indent.common").Runner --local XFAIL = require("tests.indent.common").XFAIL -local run = Runner:new(it, 'tests/indent/wgsl', { - tabstop = 2, - shiftwidth = 2, +local run = Runner:new(it, "tests/indent/wgsl", { + tabstop = 4, + shiftwidth = 4, softtabstop = 0, expandtab = true, }) -describe('indent WGSL:', function() - describe('whole file:', function() - run:whole_file('.', { +describe("indent WGSL:", function() + describe("whole file:", function() + run:whole_file(".", { expected_failures = {}, }) end) - describe('new line:', function() - run:new_line('basic.wgsl', { on_line = 47, text = 'c: u32,', indent = 2 }) - run:new_line('basic.wgsl', { on_line = 52, text = 'c: u32,', indent = 2 }) - run:new_line('basic.wgsl', { on_line = 56, text = 'c: u32,', indent = 2 }) - run:new_line('basic.wgsl', { on_line = 59, text = 'c: u32,', indent = 2 }) - run:new_line('type_constructor_or_function_call_expression.wgsl', { - on_line = 3, - text = 'b', - indent = 4, - }) - run:new_line('type_constructor_or_function_call_expression.wgsl', { - on_line = 4, - text = 'c', - indent = 4, - }) - run:new_line('type_constructor_or_function_call_expression.wgsl', { - on_line = 8, - text = 'b', - indent = 4, - }) - run:new_line('type_constructor_or_function_call_expression.wgsl', { - on_line = 9, - text = 'c', - indent = 4, - }) - end) + describe("new line:", function() end) end) diff --git a/tests/indent/yaml_spec.lua b/tests/indent/yaml_spec.lua index 001bc01f1..91c60c227 100644 --- a/tests/indent/yaml_spec.lua +++ b/tests/indent/yaml_spec.lua @@ -1,20 +1,20 @@ -local Runner = require('tests.indent.common').Runner +local Runner = require("tests.indent.common").Runner --local XFAIL = require("tests.indent.common").XFAIL -local run = Runner:new(it, 'tests/indent/yaml', { +local run = Runner:new(it, "tests/indent/yaml", { shiftwidth = 2, expandtab = true, }) -describe('indent YAML:', function() - describe('whole file:', function() - run:whole_file('.', { +describe("indent YAML:", function() + describe("whole file:", function() + run:whole_file(".", { expected_failures = {}, }) end) - describe('new line:', function() - run:new_line('indent-sequence-items.yaml', { on_line = 2, text = 'key3: value3', indent = 2 }) - run:new_line('autoindent-mapping-pair.yaml', { on_line = 1, text = 'key3: value3', indent = 2 }) + describe("new line:", function() + run:new_line("indent-sequence-items.yaml", { on_line = 2, text = "key3: value3", indent = 2 }) + run:new_line("autoindent-mapping-pair.yaml", { on_line = 1, text = "key3: value3", indent = 2 }) end) end) diff --git a/tests/indent/yang/module.yang b/tests/indent/yang/module.yang deleted file mode 100644 index 29c911fa0..000000000 --- a/tests/indent/yang/module.yang +++ /dev/null @@ -1,58 +0,0 @@ -module test-module { - yang-version 1.1; - namespace "http://example.com"; - prefix test; - - import ietf-inet-types { prefix inet; } - import tailf-ncs { - prefix ncs; - } - - description "Multi-line strings has indentation - aligned with the first line."; - - typedef foo { - type enumeration { - enum "foo"; - enum "bar"; - } - } - - ncs:plan-outline test-nano-service { - description "Testing indentation of extension statements."; - - ncs:component-type "ncs:self" { - ncs:state "ncs:init" { - ncs:create { - ncs:nano-callback; - } - } - ncs:state "ncs:ready"; - } - - ncs:component-type "alloc:resource-allocator" { - ncs:state "ncs:init"; - ncs:state "alloc:resources-allocated"; - ncs:state "ncs:ready"; - } - } - - container test { - } - - augment /alloc:resource-allocator { - description "Augmentation for the resource allocator mock services."; - - list test-nano-service { - key "id"; - - leaf id { - type string; - description - "I'm a multi-line string - - Starting on the next line from the statement."; - } - } - } -} diff --git a/tests/indent/yang_spec.lua b/tests/indent/yang_spec.lua deleted file mode 100644 index 44e1dbce5..000000000 --- a/tests/indent/yang_spec.lua +++ /dev/null @@ -1,23 +0,0 @@ -local Runner = require('tests.indent.common').Runner - -local run = Runner:new(it, 'tests/indent/yang', { - tabstop = 2, - shiftwidth = 2, - softtabstop = 0, - expandtab = true, -}) - -describe('indent YANG:', function() - describe('whole file:', function() - run:whole_file('.', { - expected_failures = {}, - }) - end) - - describe('new line:', function() - run:new_line('module.yang', { on_line = 12, text = '// Aligned indentation ended', indent = 2 }) - run:new_line('module.yang', { on_line = 37, text = '// Test', indent = 4 }) - run:new_line('module.yang', { on_line = 40, text = '// Test', indent = 4 }) - run:new_line('module.yang', { on_line = 52, text = 'Aligned string!', indent = 11 }) - end) -end) diff --git a/tests/indent/yuck/indent.yuck b/tests/indent/yuck/indent.yuck deleted file mode 100644 index c224548af..000000000 --- a/tests/indent/yuck/indent.yuck +++ /dev/null @@ -1,17 +0,0 @@ -(defwidget name - :widget parameter - (box one - :box1 parameter - (box two - :box2 parameter - ) - ) -) - -(defwidget name - :widget parameter - (box one - ) -) - -(defwidget name diff --git a/tests/indent/yuck_spec.lua b/tests/indent/yuck_spec.lua deleted file mode 100644 index b20ac8dac..000000000 --- a/tests/indent/yuck_spec.lua +++ /dev/null @@ -1,19 +0,0 @@ -local Runner = require('tests.indent.common').Runner -local run = Runner:new(it, 'tests/indent/yuck', { - tabstop = 2, - shiftwidth = 2, - expandtab = true, -}) - -describe('indent yuck', function() - describe('whole file:', function() - run:whole_file('.', { - expected_failures = {}, - }) - end) - - describe('new line:', function() - run:new_line('indent.yuck', { on_line = 13, text = ':box1 parameter', indent = 4 }) - run:new_line('indent.yuck', { on_line = 17, text = ')', indent = 0 }) - end) -end) diff --git a/tests/indent/zig_spec.lua b/tests/indent/zig_spec.lua index 4ad17446f..c064d9ab9 100644 --- a/tests/indent/zig_spec.lua +++ b/tests/indent/zig_spec.lua @@ -1,22 +1,22 @@ -local Runner = require('tests.indent.common').Runner +local Runner = require("tests.indent.common").Runner --local XFAIL = require("tests.indent.common").XFAIL -local run = Runner:new(it, 'tests/indent/zig', { +local run = Runner:new(it, "tests/indent/zig", { tabstop = 4, shiftwidth = 4, softtabstop = 4, expandtab = true, }) -describe('indent Zig:', function() - describe('whole file:', function() - run:whole_file('.', { +describe("indent Zig:", function() + describe("whole file:", function() + run:whole_file(".", { expected_failures = {}, }) end) - describe('new lines:', function() - run:new_line('pr-3269.zig', { on_line = 5, text = 'return;', indent = 4 }) - run:new_line('pr-3269.zig', { on_line = 6, text = '', indent = 0 }) + describe("new lines:", function() + run:new_line("pr-3269.zig", { on_line = 5, text = "return;", indent = 4 }) + run:new_line("pr-3269.zig", { on_line = 6, text = "", indent = 0 }) end) end) diff --git a/tests/query/highlights/bash/double-parens.sh b/tests/query/highlights/bash/double-parens.sh index 7f9209713..7ba35873e 100644 --- a/tests/query/highlights/bash/double-parens.sh +++ b/tests/query/highlights/bash/double-parens.sh @@ -1,6 +1,6 @@ -if $(( $(tree-sitter parse test/Petalisp/**/*.lisp -q | wc -l) > 2 )); then -# ^ @punctuation.special -# ^ @punctuation.special -# ^ @punctuation.bracket +if (( $(tree-sitter parse test/Petalisp/**/*.lisp -q | wc -l) > 2 )); then +# ^ punctuation.bracket +# ^ punctuation.bracket +# ^ punctuation.bracket exit 1 fi diff --git a/tests/query/highlights/capnp/test.capnp b/tests/query/highlights/capnp/test.capnp deleted file mode 100644 index b70e91358..000000000 --- a/tests/query/highlights/capnp/test.capnp +++ /dev/null @@ -1,633 +0,0 @@ -# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors -# Licensed under the MIT License: -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -@0xd508eebdc2dc42b8; -# <- @keyword.directive -# ^ @punctuation.delimiter - -using Cxx = import "c++.capnp"; -# <- @keyword.import -# ^^^ @type -# ^ @operator -# ^^^^^^ @keyword.import -# ^^^^^^^^^^^ @string.special.path - -# Use a namespace likely to cause trouble if the generated code doesn't use fully-qualified -# names for stuff in the capnproto namespace. -$Cxx.namespace("capnproto_test::capnp::test"); - -enum TestEnum { -# <- @keyword.type -# ^^^^^^^^ @type - foo @0; -# ^^^ @constant -# ^^ @label - bar @1; - baz @2; - qux @3; - quux @4; - corge @5; - grault @6; - garply @7; -} -# <- @punctuation.bracket - -struct TestAllTypes { -# <- @keyword.type - voidField @0 : Void; -# ^^^^^^^^^ @variable.member -# ^ @punctuation.special -# ^^^^ @type.builtin - boolField @1 : Bool; - int8Field @2 : Int8; - int16Field @3 : Int16; - int32Field @4 : Int32; - int64Field @5 : Int64; - uInt8Field @6 : UInt8; - uInt16Field @7 : UInt16; - uInt32Field @8 : UInt32; - uInt64Field @9 : UInt64; - float32Field @10 : Float32; - float64Field @11 : Float64; - textField @12 : Text; - dataField @13 : Data; - structField @14 : TestAllTypes; - enumField @15 : TestEnum; - interfaceField @16 : Void; # TODO - - voidList @17 : List(Void); - boolList @18 : List(Bool); - int8List @19 : List(Int8); - int16List @20 : List(Int16); - int32List @21 : List(Int32); - int64List @22 : List(Int64); - uInt8List @23 : List(UInt8); - uInt16List @24 : List(UInt16); - uInt32List @25 : List(UInt32); - uInt64List @26 : List(UInt64); - float32List @27 : List(Float32); - float64List @28 : List(Float64); - textList @29 : List(Text); - dataList @30 : List(Data); - structList @31 : List(TestAllTypes); - enumList @32 : List(TestEnum); - interfaceList @33 : List(Void); # TODO -} - -struct TestInterleavedGroups { - group1 :group { - foo @0 :UInt32; - bar @2 :UInt64; - union { -# ^^^^^ @keyword.type - qux @4 :UInt16; - corge :group { -# ^^^^^ @type - grault @6 :UInt64; - garply @8 :UInt16; - plugh @14 :Text; - xyzzy @16 :Text; - } - - fred @12 :Text; - } - - waldo @10 :Text; - } - - group2 :group { -# ^^^^^ @keyword.type - foo @1 :UInt32; - bar @3 :UInt64; - union { - qux @5 :UInt16; - corge :group { - grault @7 :UInt64; - garply @9 :UInt16; - plugh @15 :Text; - xyzzy @17 :Text; - } - - fred @13 :Text; - } - - waldo @11 :Text; - } -} - -struct TestUnionDefaults { - s16s8s64s8Set @0 :TestUnion = - (union0 = (u0f0s16 = 321), union1 = (u1f0s8 = 123), union2 = (u2f0s64 = 12345678901234567), -# ^^^ @number - union3 = (u3f0s8 = 55)); - s0sps1s32Set @1 :TestUnion = - (union0 = (u0f1s0 = void), union1 = (u1f0sp = "foo"), union2 = (u2f0s1 = true), -# ^^^^^ @string -# ^^^^ @boolean - union3 = (u3f0s32 = 12345678)); - - unnamed1 @2 :TestUnnamedUnion = (foo = 123); - unnamed2 @3 :TestUnnamedUnion = (bar = 321, before = "foo", after = "bar"); -} - -struct TestUsing { - using OuterNestedEnum = TestNestedTypes.NestedEnum; -# ^^^^^ @keyword.import - using TestNestedTypes.NestedStruct.NestedEnum; - - outerNestedEnum @1 :OuterNestedEnum = bar; - innerNestedEnum @0 :NestedEnum = quux; -} - -struct TestListDefaults { - lists @0 :TestLists = ( - list0 = [(f = void), (f = void)], -# ^^^^ @constant.builtin - list1 = [(f = true), (f = false), (f = true), (f = true)], - list8 = [(f = 123), (f = 45)], - list16 = [(f = 12345), (f = 6789)], - list32 = [(f = 123456789), (f = 234567890)], - list64 = [(f = 1234567890123456), (f = 2345678901234567)], - listP = [(f = "foo"), (f = "bar")], - int32ListList = [[1, 2, 3], [4, 5], [12341234]], - textListList = [["foo", "bar"], ["baz"], ["qux", "corge"]], - structListList = [[(int32Field = 123), (int32Field = 456)], [(int32Field = 789)]]); -} - -struct TestWholeFloatDefault { - # At one point, these failed to compile in C++ because it would produce literals like "123f", - # which is not valid; it needs to be "123.0f". - field @0 :Float32 = 123; - bigField @1 :Float32 = 2e30; - const constant :Float32 = 456; - const bigConstant :Float32 = 4e30; -# ^^^^ @number.float -} - -struct TestGenerics(Foo, Bar) { - foo @0 :Foo; - rev @1 :TestGenerics(Bar, Foo); - - union { - uv @2:Void; - ug :group { - ugfoo @3:Int32; - } - } - - list @4 :List(Inner); - # At one time this failed to compile with MSVC due to poor expression SFINAE support. - - struct Inner { - foo @0 :Foo; - bar @1 :Bar; - } - - struct Inner2(Baz) { - bar @0 :Bar; - baz @1 :Baz; - innerBound @2 :Inner; - innerUnbound @3 :TestGenerics.Inner; - - struct DeepNest(Qux) { - foo @0 :Foo; - bar @1 :Bar; - baz @2 :Baz; - qux @3 :Qux; - - interface DeepNestInterface(Quux) { -# ^^^^^^^^^ @keyword.type - # At one time this failed to compile. - call @0 () -> (); -# ^^^^ @function.method -# ^^ @punctuation.delimiter - } - } - } - - interface Interface(Qux) { - call @0 Inner2(Text) -> (qux :Qux, gen :TestGenerics(TestAllTypes, TestAnyPointer)); -# ^^^ @variable.parameter -# ^^^ @variable.parameter - } - - annotation ann(struct) :Foo; -# ^^^^^^^^^^ @keyword.type -# ^^^ @function.method -# ^^^^^^ @variable.parameter.builtin - - using AliasFoo = Foo; - using AliasInner = Inner; - using AliasInner2 = Inner2; - using AliasInner2Text = Inner2(Text); - using AliasRev = TestGenerics(Bar, Foo); - - struct UseAliases { - foo @0 :AliasFoo; - inner @1 :AliasInner; - inner2 @2 :AliasInner2; - inner2Bind @3 :AliasInner2(Text); - inner2Text @4 :AliasInner2Text; - revFoo @5 :AliasRev.AliasFoo; - } -} - -struct BoxedText { text @0 :Text; } -using BrandedAlias = TestGenerics(BoxedText, Text); - -struct TestGenericsWrapper(Foo, Bar) { - value @0 :TestGenerics(Foo, Bar); -} - -struct TestGenericsWrapper2 { - value @0 :TestGenericsWrapper(Text, TestAllTypes); -} - -interface TestImplicitMethodParams { - call @0 [T, U] (foo :T, bar :U) -> TestGenerics(T, U); -# ^ @type -# ^ @type -} - -interface TestImplicitMethodParamsInGeneric(V) { - call @0 [T, U] (foo :T, bar :U) -> TestGenerics(T, U); -} - -struct TestGenericsUnion(Foo, Bar) { - # At one point this failed to compile. - - union { - foo @0 :Foo; - bar @1 :Bar; - } -} - -struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") { -# ^ @punctuation.special -# ^^^^^^^^^^^^ @attribute -# ^ @punctuation.delimiter -# ^^^ @attribute - basic @0 :TestGenerics(TestAllTypes, TestAnyPointer); - inner @1 :TestGenerics(TestAllTypes, TestAnyPointer).Inner; - inner2 @2 :TestGenerics(TestAllTypes, TestAnyPointer).Inner2(Text); - unspecified @3 :TestGenerics; - unspecifiedInner @4 :TestGenerics.Inner2(Text); - wrapper @8 :TestGenericsWrapper(TestAllTypes, TestAnyPointer); - cap @18 :TestGenerics(TestInterface, Text); - genericCap @19 :TestGenerics(TestAllTypes, List(UInt32)).Interface(Data); - - default @5 :TestGenerics(TestAllTypes, Text) = - (foo = (int16Field = 123), rev = (foo = "text", rev = (foo = (int16Field = 321)))); - defaultInner @6 :TestGenerics(TestAllTypes, Text).Inner = - (foo = (int16Field = 123), bar = "text"); - defaultUser @7 :TestUseGenerics = (basic = (foo = (int16Field = 123))); - defaultWrapper @9 :TestGenericsWrapper(Text, TestAllTypes) = - (value = (foo = "text", rev = (foo = (int16Field = 321)))); - defaultWrapper2 @10 :TestGenericsWrapper2 = - (value = (value = (foo = "text", rev = (foo = (int16Field = 321))))); - - aliasFoo @11 :TestGenerics(TestAllTypes, TestAnyPointer).AliasFoo = (int16Field = 123); - aliasInner @12 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner - = (foo = (int16Field = 123)); - aliasInner2 @13 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2 - = (innerBound = (foo = (int16Field = 123))); - aliasInner2Bind @14 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2(List(UInt32)) - = (baz = [12, 34], innerBound = (foo = (int16Field = 123))); - aliasInner2Text @15 :TestGenerics(TestAllTypes, TestAnyPointer).AliasInner2Text - = (baz = "text", innerBound = (foo = (int16Field = 123))); - aliasRev @16 :TestGenerics(TestAnyPointer, Text).AliasRev.AliasFoo = "text"; - - useAliases @17 :TestGenerics(TestAllTypes, List(UInt32)).UseAliases = ( - foo = (int16Field = 123), - inner = (foo = (int16Field = 123)), - inner2 = (innerBound = (foo = (int16Field = 123))), - inner2Bind = (baz = "text", innerBound = (foo = (int16Field = 123))), - inner2Text = (baz = "text", innerBound = (foo = (int16Field = 123))), - revFoo = [12, 34, 56]); -} - -struct TestEmptyStruct {} - -struct TestConstants { - const voidConst :Void = void; -# ^^^^^ @keyword.modifier - const boolConst :Bool = true; - const int8Const :Int8 = -123; - const int16Const :Int16 = -12345; - const int32Const :Int32 = -12345678; - const int64Const :Int64 = -123456789012345; - const uint8Const :UInt8 = 234; - const uint16Const :UInt16 = 45678; - const uint32Const :UInt32 = 3456789012; - const uint64Const :UInt64 = 12345678901234567890; - const float32Const :Float32 = 1234.5; - const float64Const :Float64 = -123e45; - const textConst :Text = "foo"; - const dataConst :Data = "bar"; - const structConst :TestAllTypes = ( - voidField = void, - boolField = true, - int8Field = -12, - int16Field = 3456, - int32Field = -78901234, - int64Field = 56789012345678, - uInt8Field = 90, - uInt16Field = 1234, - uInt32Field = 56789012, - uInt64Field = 345678901234567890, - float32Field = -1.25e-10, - float64Field = 345, - textField = "baz", - dataField = "qux", - structField = ( - textField = "nested", - structField = (textField = "really nested")), - enumField = baz, - # interfaceField can't have a default - - voidList = [void, void, void], - boolList = [false, true, false, true, true], - int8List = [12, -34, -0x80, 0x7f], - int16List = [1234, -5678, -0x8000, 0x7fff], - int32List = [12345678, -90123456, -0x80000000, 0x7fffffff], - int64List = [123456789012345, -678901234567890, -0x8000000000000000, 0x7fffffffffffffff], - uInt8List = [12, 34, 0, 0xff], - uInt16List = [1234, 5678, 0, 0xffff], - uInt32List = [12345678, 90123456, 0, 0xffffffff], - uInt64List = [123456789012345, 678901234567890, 0, 0xffffffffffffffff], - float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], - float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], - textList = ["quux", "corge", "grault"], - dataList = ["garply", "waldo", "fred"], - structList = [ - (textField = "x " "structlist" - " 1"), - (textField = "x structlist 2"), - (textField = "x structlist 3")], - enumList = [qux, bar, grault] - # interfaceList can't have a default - ); - const enumConst :TestEnum = corge; - - const voidListConst :List(Void) = [void, void, void, void, void, void]; - const boolListConst :List(Bool) = [true, false, false, true]; - const int8ListConst :List(Int8) = [111, -111]; - const int16ListConst :List(Int16) = [11111, -11111]; - const int32ListConst :List(Int32) = [111111111, -111111111]; - const int64ListConst :List(Int64) = [1111111111111111111, -1111111111111111111]; - const uint8ListConst :List(UInt8) = [111, 222] ; - const uint16ListConst :List(UInt16) = [33333, 44444]; - const uint32ListConst :List(UInt32) = [3333333333]; - const uint64ListConst :List(UInt64) = [11111111111111111111]; - const float32ListConst :List(Float32) = [5555.5, inf, -inf, nan]; - const float64ListConst :List(Float64) = [7777.75, inf, -inf, nan]; - const textListConst :List(Text) = ["plugh", "xyzzy", "thud"]; - const dataListConst :List(Data) = ["oops", "exhausted", "rfc3092"]; - const structListConst :List(TestAllTypes) = [ - (textField = "structlist 1"), - (textField = "structlist 2"), - (textField = "structlist 3")]; - const enumListConst :List(TestEnum) = [foo, garply]; -} - -const globalInt :UInt32 = 12345; -const globalText :Text = "foobar"; -const globalStruct :TestAllTypes = (int32Field = 54321); -const globalPrintableStruct :TestPrintInlineStructs = (someText = "foo"); -const derivedConstant :TestAllTypes = ( - uInt32Field = .globalInt, - textField = TestConstants.textConst, - structField = TestConstants.structConst, - int16List = TestConstants.int16ListConst, - structList = TestConstants.structListConst); - -const genericConstant :TestGenerics(TestAllTypes, Text) = - (foo = (int16Field = 123), rev = (foo = "text", rev = (foo = (int16Field = 321)))); - -const embeddedData :Data = embed "testdata/packed"; -# ^^^^^ @keyword.import -const embeddedText :Text = embed "testdata/short.txt"; -const embeddedStruct :TestAllTypes = embed "testdata/binary"; - -const nonAsciiText :Text = "♫ é ✓"; - -const blockText :Text = - `foo bar baz - `"qux" `corge` 'grault' - "regular\"quoted\"line" - `garply\nwaldo\tfred\"plugh\"xyzzy\'thud - ; - -struct TestAnyPointerConstants { - anyKindAsStruct @0 :AnyPointer; - anyStructAsStruct @1 :AnyStruct; - anyKindAsList @2 :AnyPointer; - anyListAsList @3 :AnyList; -} - -const anyPointerConstants :TestAnyPointerConstants = ( - anyKindAsStruct = TestConstants.structConst, - anyStructAsStruct = TestConstants.structConst, - anyKindAsList = TestConstants.int32ListConst, - anyListAsList = TestConstants.int32ListConst, -); - -interface TestInterface { - foo @0 (i :UInt32, j :Bool) -> (x :Text); -# ^ @variable.parameter - bar @1 () -> (); - baz @2 (s: TestAllTypes); -} - -interface TestExtends extends(TestInterface) { -# ^^^^^^^ @keyword - qux @0 (); - corge @1 TestAllTypes -> (); - grault @2 () -> TestAllTypes; -} - -interface TestTailCallee $Cxx.allowCancellation { - struct TailResult { - i @0 :UInt32; - t @1 :Text; - c @2 :TestCallOrder; - } - - foo @0 (i :Int32, t :Text) -> TailResult; -} - -interface TestTailCaller { - foo @0 (i :Int32, callee :TestTailCallee) -> TestTailCallee.TailResult; -} - -interface TestStreaming $Cxx.allowCancellation { - doStreamI @0 (i :UInt32) -> stream; - doStreamJ @1 (j :UInt32) -> stream; - finishStream @2 () -> (totalI :UInt32, totalJ :UInt32); - # Test streaming. finishStream() returns the totals of the values streamed to the other calls. -} - -interface TestHandle {} - -interface TestMoreStuff extends(TestCallOrder) { - # Catch-all type that contains lots of testing methods. - - callFoo @0 (cap :TestInterface) -> (s: Text); - # Call `cap.foo()`, check the result, and return "bar". - - callFooWhenResolved @1 (cap :TestInterface) -> (s: Text); - # Like callFoo but waits for `cap` to resolve first. - - neverReturn @2 (cap :TestInterface) -> (capCopy :TestInterface) $Cxx.allowCancellation; - # Doesn't return. You should cancel it. - - hold @3 (cap :TestInterface) -> (); - # Returns immediately but holds on to the capability. - - callHeld @4 () -> (s: Text); - # Calls the capability previously held using `hold` (and keeps holding it). - - getHeld @5 () -> (cap :TestInterface); - # Returns the capability previously held using `hold` (and keeps holding it). - - echo @6 (cap :TestCallOrder) -> (cap :TestCallOrder); - # Just returns the input cap. - - expectCancel @7 (cap :TestInterface) -> () $Cxx.allowCancellation; - # evalLater()-loops forever, holding `cap`. Must be canceled. - - methodWithDefaults @8 (a :Text, b :UInt32 = 123, c :Text = "foo") -> (d :Text, e :Text = "bar"); - - methodWithNullDefault @12 (a :Text, b :TestInterface = null); - - getHandle @9 () -> (handle :TestHandle); - # Get a new handle. Tests have an out-of-band way to check the current number of live handles, so - # this can be used to test garbage collection. - - getNull @10 () -> (nullCap :TestMoreStuff); - # Always returns a null capability. - - getEnormousString @11 () -> (str :Text); - # Attempts to return an 100MB string. Should always fail. - - writeToFd @13 (fdCap1 :TestInterface, fdCap2 :TestInterface) - -> (fdCap3 :TestInterface, secondFdPresent :Bool); - # Expects fdCap1 and fdCap2 wrap socket file descriptors. Writes "foo" to the first and "bar" to - # the second. Also creates a socketpair, writes "baz" to one end, and returns the other end. - - throwException @14 (); - throwRemoteException @15 (); -} - -interface TestMembrane { - makeThing @0 () -> (thing :Thing); - callPassThrough @1 (thing :Thing, tailCall :Bool) -> Result; - callIntercept @2 (thing :Thing, tailCall :Bool) -> Result; - loopback @3 (thing :Thing) -> (thing :Thing); - - waitForever @4 () $Cxx.allowCancellation; - - interface Thing { - passThrough @0 () -> Result; - intercept @1 () -> Result; - } - - struct Result { - text @0 :Text; - } -} - -struct TestNameAnnotation $Cxx.name("RenamedStruct") { - union { - badFieldName @0 :Bool $Cxx.name("goodFieldName"); - bar @1 :Int8; - } - - enum BadlyNamedEnum $Cxx.name("RenamedEnum") { - foo @0; - bar @1; - baz @2 $Cxx.name("qux"); - } - - anotherBadFieldName @2 :BadlyNamedEnum $Cxx.name("anotherGoodFieldName"); - - struct NestedStruct $Cxx.name("RenamedNestedStruct") { - badNestedFieldName @0 :Bool $Cxx.name("goodNestedFieldName"); - anotherBadNestedFieldName @1 :NestedStruct $Cxx.name("anotherGoodNestedFieldName"); - - enum DeeplyNestedEnum $Cxx.name("RenamedDeeplyNestedEnum") { - quux @0; - corge @1; - grault @2 $Cxx.name("garply"); - } - } - - badlyNamedUnion :union $Cxx.name("renamedUnion") { - badlyNamedGroup :group $Cxx.name("renamedGroup") { - foo @3 :Void; - bar @4 :Void; - } - baz @5 :NestedStruct $Cxx.name("qux"); - } -} - -interface TestNameAnnotationInterface $Cxx.name("RenamedInterface") { - badlyNamedMethod @0 (badlyNamedParam :UInt8 $Cxx.name("renamedParam")) $Cxx.name("renamedMethod"); -} - -struct TestImpliedFirstField { - struct TextStruct { - text @0 :Text; - i @1 :UInt32 = 321; - } - - textStruct @0 :TextStruct = "foo"; - textStructList @1 :List(TextStruct); - - intGroup :group { - i @2 :UInt32; - str @3 :Text = "corge"; - } -} - -const testImpliedFirstField :TestImpliedFirstField = ( - textStruct = "bar", - textStructList = ["baz", (text = "qux", i = 123)], - intGroup = 123 -); - -struct TestCycleANoCaps { - foo @0 :TestCycleBNoCaps; -} - -struct TestCycleBNoCaps { - foo @0 :List(TestCycleANoCaps); - bar @1 :TestAllTypes; -} - -struct TestCycleAWithCaps { - foo @0 :TestCycleBWithCaps; -} - -struct TestCycleBWithCaps { - foo @0 :List(TestCycleAWithCaps); - bar @1 :TestInterface; -} diff --git a/tests/query/highlights/clojure/test.clj b/tests/query/highlights/clojure/test.clj deleted file mode 100644 index 7401019e8..000000000 --- a/tests/query/highlights/clojure/test.clj +++ /dev/null @@ -1,114 +0,0 @@ -(ns test {:clj-kondo/ignore true}) -; <- @punctuation.bracket -; ^ @keyword.import -; ^ @module - - ; asdf -;^^^^^^ @comment - - #_ abc -;^^^^^^ @comment - -(func obj) -;^^^^ @function.call -; ^^^ @variable - - #(+ % %1 %& %a) -;^ @punctuation.special -; ^ @function.call -; ^ ^^ ^^ @variable.builtin -; ^^ @variable - - abc# -;^^^^ @variable - - & -;^ @variable.parameter - - ->abc -;^^^^^ @constructor - - ->>abc -;^^^^^^ @variable - - *1 *2 *3 *e -;^^ ^^ ^^ ^^ @variable.builtin - - .method -;^^^^^^^ @function.method - -(.method foo) -;^^^^^^^ @function.method - -(.-field foo) -;^^^^^^^ @variable.member - - Abc/member -;^^^^^^^^^^ @variable.member - -(Abc/method) -;^^^^^^^^^^ @function.method - - Abc -;^^^ @type - - abc. -;^^^^ @type - - ^abc -;^ @punctuation.special - -^java.io.File file -; <- @punctuation.special -;^^^^^^^^^^^^ @type -; ^^^^ @variable - -^java.io.File java.io.File. -; <- @punctuation.special -;^^^^^^^^^^^^ @type -; ^^^^ @variable - -^java.io.File file. -; <- @punctuation.special -;^^^^^^^^^^^^ @type -; ^^^^ @variable - -(^java.io.File file) -;^ @punctuation.special -; ^^^^^^^^^^^^ @type -; ^^^^ @function.call - -(^java.io.File .file foo) -;^ @punctuation.special -; ^^^^^^^^^^^^ @type -; ^^^^ @function.method -; ^^^@variable - -(^java.io.File .-file foo) -;^ @punctuation.special -; ^^^^^^^^^^^^ @type -; ^^^^ @variable.member -; ^^^@variable - -(^java.io.File Abc/method foo) -;^ @punctuation.special -; ^^^^^^^^^^^^ @type -; ^^^^^^^^^^ @function.method -; ^^^ @variable - - (defn foo [arg1] (+ arg1 1)) -;^ ^ ^ ^ ^^ @punctuation.bracket -; ^^^^ @keyword.function -; ^^^ @function -; ^^^^ ^^^^ @variable -; ^ @operator -; ^ @number - - clojure.core/dfn -;^^^^^^^^^^^^^^^^ @variable - - clojure.core/defn -;^^^^^^^^^^^^^^^^ @keyword.function - - any-ns/defn -;^^^^^^^^^^^ @keyword.function diff --git a/tests/query/highlights/cpp/concepts.cpp b/tests/query/highlights/cpp/concepts.cpp index 3189813bc..27aed7a70 100644 --- a/tests/query/highlights/cpp/concepts.cpp +++ b/tests/query/highlights/cpp/concepts.cpp @@ -1,14 +1,14 @@ template concept Derived = std::is_base_of::value; -// ^ @keyword.type -// ^ @type.definition +// ^ keyword +// ^ type.definition template concept Hashable = requires(T a) { -// ^ @keyword -// ^ @variable.parameter -// ^ @type +// ^ keyword +// ^ parameter +// ^ type { std::hash{}(a) } -> std::convertible_to; typename CommonType; // CommonType is valid and names a type { CommonType{std::forward(t)} }; @@ -18,5 +18,5 @@ concept Hashable = requires(T a) { template requires requires (T x) { x + x; } // ad-hoc constraint, note keyword used twice -// ^ @keyword +// ^ keyword T add(T a, T b) { return a + b; } diff --git a/tests/query/highlights/cpp/enums-as-constants.cpp b/tests/query/highlights/cpp/enums-as-constants.cpp index d6b93d5ec..ae773e8d3 100644 --- a/tests/query/highlights/cpp/enums-as-constants.cpp +++ b/tests/query/highlights/cpp/enums-as-constants.cpp @@ -11,7 +11,7 @@ void foo(Foo f){ switch ( f ) { case Foo::a: // ^ @type - // ^ @module + // ^ @namespace // ^ @constant break; case Foo::aa: diff --git a/tests/query/highlights/cpp/static-namespace-functions.cpp b/tests/query/highlights/cpp/static-namespace-functions.cpp index 3d16c43cf..2bea488a3 100644 --- a/tests/query/highlights/cpp/static-namespace-functions.cpp +++ b/tests/query/highlights/cpp/static-namespace-functions.cpp @@ -1,14 +1,12 @@ // Issue #2396 -int main() -{ - B::foo(); +int main() +{ + B::foo(); // ^ @function.call - Foo::A::foo(); + Foo::A::foo(); // ^ @function.call - Foo::a::A::foo(); + Foo::a::A::foo(); // ^ @function.call - Foo::a::A::B::foo(); - // ^ @function.call - return 0; -} + return 0; +} diff --git a/tests/query/highlights/cpp/test.cpp b/tests/query/highlights/cpp/test.cpp index 4a4c6238a..77e3be698 100644 --- a/tests/query/highlights/cpp/test.cpp +++ b/tests/query/highlights/cpp/test.cpp @@ -1,19 +1,19 @@ #include #include -// ^ @keyword.import -// ^ @string +// ^ include +// ^ string auto main( int argc, char** argv ) -> int -// ^ @type.builtin - // ^ @variable.parameter - // ^ @type.builtin - // ^ @type.builtin - // ^ @operator +// ^ type.builtin + // ^ parameter + // ^ type.builtin + // ^ type.builtin + // ^ operator { std::cout << "Hello world!" << std::endl; - // ^ @punctuation.delimiter + // ^ punctuation.delimiter return EXIT_SUCCESS; - // ^ @keyword.return - // ^ @constant + // ^ keyword.return + // ^ constant } diff --git a/tests/query/highlights/ecma/const.js b/tests/query/highlights/ecma/const.js deleted file mode 100644 index 2b778fd15..000000000 --- a/tests/query/highlights/ecma/const.js +++ /dev/null @@ -1,13 +0,0 @@ -_FOO = 4 -// <- @constant -__A__ = 2 -// <- @constant -_ = 2 -// <- @variable -A_B_C = 4 -// <- @constant -_1 = 1 -// <- @variable - -const A = 2 -// ^ @constant diff --git a/tests/query/highlights/ecma/test.ts b/tests/query/highlights/ecma/test.ts index fa926f930..d35cf8272 100644 --- a/tests/query/highlights/ecma/test.ts +++ b/tests/query/highlights/ecma/test.ts @@ -1,32 +1,32 @@ class H { pub_field = "Hello"; - // ^ @variable.member + // ^ property #priv_field = "World!"; - // ^ @variable.member + // ^ property #private_method() { - // ^ @function.method + // ^ method return `${this.pub_field} -- ${this.#priv_field}`; - // ^ @variable.member - // ^ @variable.member + // ^ property + // ^ property } public_method() { - // ^ @function.method + // ^ method return this.#private_method(); - // ^ @function.method.call + // ^ method.call } ok() { return this.public_method(); - // ^ @function.method.call + // ^ method.call } } function doSomething(options) { const { enable: on, - // ^ @punctuation.delimiter + // ^ punctuation.delimiter } = options } diff --git a/tests/query/highlights/fusion/afx.fusion b/tests/query/highlights/fusion/afx.fusion new file mode 100644 index 000000000..4ccb8174f --- /dev/null +++ b/tests/query/highlights/fusion/afx.fusion @@ -0,0 +1,17 @@ +property = afx` + + + +
text
+ + + + + + + true} /> + + + + +` diff --git a/tests/query/highlights/fusion/basic.fusion b/tests/query/highlights/fusion/basic.fusion new file mode 100644 index 000000000..e4c4d6afc --- /dev/null +++ b/tests/query/highlights/fusion/basic.fusion @@ -0,0 +1,60 @@ +include: SomeFile.fusion +//<- include +// ^text.uri + +namespace: ns = Neos.Fusion.Space +//<- keyword +// ^namespace +// ^operator +// ^namespace + +prototype(MyType) < prototype(ns:SuperType) { +//<-keyword +// ^punctuation.bracket +// ^type +// ^punctuation.bracket +// ^operator +// ^namespace +// ^type + + deleteProp > + // ^operator + + string = 'value' + //<- property + // ^operator + // ^string + + number = 10.2 + // ^number + + null = null + // ^constant.builtin + + boolean = true + // ^boolean + + property.inner = "value" + //<- property + // ^property + + property.@meta = "value" + //<- property + // ^attribute + + property.type = SomeType + //<- property + // ^type + + property.aliasedType = ns:SomeType + //<- property + // ^namespace + // ^type + + property.fullQualifiedType = SomeNamespace:SomeType + //<- property + // ^namespace + // ^type + +} + diff --git a/tests/query/highlights/fusion/expressions.fusion b/tests/query/highlights/fusion/expressions.fusion new file mode 100644 index 000000000..ae6e2db33 --- /dev/null +++ b/tests/query/highlights/fusion/expressions.fusion @@ -0,0 +1,82 @@ +string = ${'foo'} +// ^string + +string = ${'foo \'bar\' baz'} +// ^string + +string = ${"foo"} +// ^string + +string = ${"foo ${test}"} +// ^string + +boolean = ${true} +// ^boolean + +number = ${1} +// ^number + +number = ${1.2} +// ^number + +propertyPath = ${property.path} +// ^variable +// ^variable + +thisorProps = ${this.path} +// ^variable.builtin +// ^variable + +thisorProps = ${props.path} +// ^variable.builtin +// ^variable + +array = ${[]} +// ^punctuation.bracket + +array = ${[true, 'string', 1, [true]]} +// ^punctuation.bracket +// ^boolean +// ^string +// ^number +// ^punctuation.bracket +// ^boolean + +object = ${{}} +// ^punctuation.bracket + +object = ${{first: 'value', second: true, third: [], fourth: object.path }} +// ^property +// ^string +// ^property +// ^boolean +// ^property +// ^punctuation.bracket +// ^property +// ^variable + +result = ${methodCall()} +// ^function + +result = ${Some.methodCall(param, param)} +// ^function +// ^variable +// ^variable + +arrowFunction = ${map(foo, (bar, buz) => bar * buz)} +// ^function +// ^variable +// ^variable + +logic = ${!foo && !(bar || baz) and not 'string'} +// ^operator +// ^operator +// ^operator +// ^operator +// ^operator + +ternary = ${ check ? true : false} +// ^@conditional.ternary +// ^@conditional.ternary + + diff --git a/tests/query/highlights/gdshader/test.gdshader b/tests/query/highlights/gdshader/test.gdshader deleted file mode 100644 index db1459028..000000000 --- a/tests/query/highlights/gdshader/test.gdshader +++ /dev/null @@ -1,26 +0,0 @@ -shader_type spatial; - -render_mode unshaded, wireframe; -// <- @keyword -// ^^^^^^^^ @keyword -// ^^^^^^^^^ @keyword - -/** My Doc comment*/ -//^^^^^^^^^^^^^^^^^^ @comment.documentation -uniform float MY_VALUE: interesting_hint = 1.0; -//<- @keyword -// ^^^^^ type.builtin -// ^^^^^^^^ constant -// ^ @punctuation.delimiter -// ^^^^^^^^^^^^^^^^ @attribute -// ^ @operator -// ^^^ @number.float -// ^ punctuation.delimiter - -void vertex() { -// <- type.builtin -// ^^^^^^ @function - do {} while (123< 2231); -//^^ keyword.repeat -// ^^^^^ keyword.repeat -} diff --git a/tests/query/highlights/gitattributes/test.gitattributes b/tests/query/highlights/gitattributes/test.gitattributes index 4595b94f2..1d398db41 100644 --- a/tests/query/highlights/gitattributes/test.gitattributes +++ b/tests/query/highlights/gitattributes/test.gitattributes @@ -1,37 +1,37 @@ [attr]nodiff -diff -merge -# <- @keyword.directive -# ^^^^^^ @property -# ^ @operator -# ^^^^ @variable.builtin -# ^ @operator -# ^^^^^ @variable.builtin +# <- preproc +# ^^^^^^ property +# ^ operator +# ^^^^ variable.builtin +# ^ operator +# ^^^^^ variable.builtin vendor/** linguist-vendored=true -# ^ @punctuation.delimiter -# ^^ @character.special -# ^^^^^^^^^^^^^^^^^ @variable.parameter -# ^ @operator -# ^^^^ @boolean +# ^ punctuation.delimiter +# ^^ character.special +# ^^^^^^^^^^^^^^^^^ parameter +# ^ operator +# ^^^^ boolean [^._]-[[:lower:]] !something -# ^ @punctuation.bracket -# ^ @operator -# ^^ @string.special -# ^ @punctuation.bracket -# ^ @punctuation.bracket -# ^^^^^^^^^ @constant -# ^ @punctuation.bracket -# ^ @operator -# ^^^^^^^^^^ @variable.parameter +# ^ punctuation.bracket +# ^ operator +# ^^ string.special +# ^ punctuation.bracket +# ^ punctuation.bracket +# ^^^^^^^^^ constant +# ^ punctuation.bracket +# ^ operator +# ^^^^^^^^^^ parameter "_\u4E00\t\56txt" encoding=UTF-16 -# <- @punctuation.special -# ^^^^^^ @string.escape -# ^^ @string.escape -# ^^^ @string.escape -# ^ @punctuation.special -# ^^^^^^^^ @variable.builtin -# ^ @operator -# ^^^^^^ @string +# <- punctuation.special +# ^^^^^^ string.escape +# ^^ string.escape +# ^^^ string.escape +# ^ punctuation.special +# ^^^^^^^^ variable.builtin +# ^ operator +# ^^^^^^ string # vim:ft=gitattributes: diff --git a/tests/query/highlights/gleam/assert.gleam b/tests/query/highlights/gleam/assert.gleam index fd95304ac..e49b3d2c4 100644 --- a/tests/query/highlights/gleam/assert.gleam +++ b/tests/query/highlights/gleam/assert.gleam @@ -1,13 +1,13 @@ pub fn main() { - assert Ok(i) == parse_int("123") - // <- @keyword.exception - // ^^ @constructor - // ^ @punctuation.bracket - // ^ @variable - // ^ @punctuation.bracket - // ^ @operator - // ^^^^^^^^^ @function.call - // ^ @punctuation.bracket - // ^^^^^ @string - // ^ @punctuation.bracket + assert Ok(i) = parse_int("123") + // <- exception + // ^ type + // ^ punctuation.bracket + // ^ variable + // ^ punctuation.bracket + // ^ operator + // ^ function + // ^ punctuation.bracket + // ^ string + // ^ punctuation.bracket } diff --git a/tests/query/highlights/gleam/function.gleam b/tests/query/highlights/gleam/function.gleam index 15fc5cc7e..bc69ec620 100644 --- a/tests/query/highlights/gleam/function.gleam +++ b/tests/query/highlights/gleam/function.gleam @@ -1,127 +1,127 @@ pub fn add(x: Int, y: Int) -> Int { -// <- @keyword.modifier -// ^^ @keyword.function -// ^^^ @function -// ^ @punctuation.bracket -// ^ @variable.parameter -// ^ @punctuation.delimiter -// ^^^ @type -// ^ @punctuation.delimiter -// ^ @variable.parameter -// ^ @punctuation.delimiter -// ^^^ @type -// ^ @punctuation.bracket -// ^ @punctuation.delimiter -// ^^^ @type -// ^ @punctuation.bracket +// <- type.qualifier +// ^ keyword.function +// ^ function +// ^ punctuation.bracket +// ^ parameter +// ^ parameter +// ^ type +// ^ punctuation.delimiter +// ^ parameter +// ^ parameter +// ^ type +// ^ punctuation.bracket +// ^ operator +// ^ type +// ^ punctuation.bracket } -// <- @punctuation.bracket +// <- punctuation.bracket pub fn twice(f: fn(t) -> t, x: t) -> t { -// <- @keyword.modifier -// ^ @keyword.function -// ^^^^^ @function -// ^ @punctuation.bracket -// ^ @variable.parameter -// ^ @punctuation.delimiter -// ^^ @keyword.function -// ^ @punctuation.bracket -// ^ @type -// ^ @punctuation.bracket -// ^^ @punctuation.delimiter -// ^ @type -// ^ @punctuation.delimiter -// ^ @variable.parameter -// ^ @punctuation.delimiter -// ^ @type -// ^ @punctuation.bracket -// ^^ @punctuation.delimiter -// ^ @type -// ^ @punctuation.bracket +// <- type.qualifier +// ^ keyword.function +// ^ function +// ^ punctuation.bracket +// ^ parameter +// ^ parameter +// ^ keyword.function +// ^ punctuation.bracket +// ^ type +// ^ punctuation.bracket +// ^ operator +// ^ type +// ^ punctuation.delimiter +// ^ parameter +// ^ parameter +// ^ type +// ^ punctuation.bracket +// ^ operator +// ^ type +// ^ punctuation.bracket } -// <- @punctuation.bracket +// <- punctuation.bracket fn list_of_two(my_value: a) -> List(a) { -// <- @keyword.function -// ^ @function -// ^ @punctuation.bracket -// ^ @variable.parameter -// ^ @punctuation.delimiter -// ^ @type -// ^ @punctuation.bracket -// ^ @punctuation.delimiter -// ^^^^ @type -// ^ @punctuation.bracket -// ^ @type -// ^ @punctuation.bracket -// ^ @punctuation.bracket +// <- keyword.function +// ^ function +// ^ punctuation.bracket +// ^ parameter +// ^ parameter +// ^ type +// ^ punctuation.bracket +// ^ operator +// ^ type +// ^ punctuation.bracket +// ^ type +// ^ punctuation.bracket +// ^ punctuation.bracket } -// <- @punctuation.bracket +// <- punctuation.bracket fn replace( -// <- @keyword.function -// ^^^^^^^ @function -// ^ @punctuation.bracket +// <- keyword.function +// ^ function +// ^ punctuation.bracket in string: String, - // <- @label - // ^^^^^^ @variable.parameter - // ^ @punctuation.delimiter - // ^^^^^^ @type - // ^ @punctuation.delimiter + // <- symbol + // ^ parameter + // ^ parameter + // ^ type + // ^ punctuation.delimiter each pattern: String, - // <- @label - // ^^^^^^^ @variable.parameter - // ^ @punctuation.delimiter - // ^^^^^^ @type - // ^ @punctuation.delimiter + // <- symbol + // ^ parameter + // ^ parameter + // ^ type + // ^ punctuation.delimiter with replacement: String, - // <- @label - // ^^^^^^^^^^^ @variable.parameter - // ^ @punctuation.delimiter - // ^^^^^^ @type - // ^ @punctuation.delimiter + // <- symbol + // ^ parameter + // ^ parameter + // ^ type + // ^ punctuation.delimiter ) { replace(in: "A,B,C", each: ",", with: " ") - // <- @function.call - // ^ @punctuation.bracket - // ^^ @label - // ^ @punctuation.delimiter - // ^^^^^^^ @string - // ^ @punctuation.delimiter - // ^^^^ @label - // ^ @punctuation.delimiter - // ^^^ @string - // ^ @punctuation.delimiter - // ^^^^ @label - // ^ @punctuation.delimiter - // ^^^ @string - // ^ @punctuation.bracket + // <- function + // ^ punctuation.bracket + // ^ symbol + // ^ symbol + // ^ string + // ^ punctuation.delimiter + // ^ symbol + // ^ symbol + // ^ string + // ^ punctuation.delimiter + // ^ symbol + // ^ symbol + // ^ string + // ^ punctuation.bracket } -// <- @punctuation.bracket +// <- punctuation.bracket pub external fn random_float() -> Float = "rand" "uniform" -// <- @keyword.modifier -// ^^^^^^^^ @keyword.modifier -// ^^ @keyword.function -// ^^^^^^^^^^^^ @function -// ^ @punctuation.bracket -// ^ @punctuation.bracket -// ^^ @punctuation.delimiter -// ^^^^^ @type -// ^ @operator -// ^^^^^^ @module -// ^^^^^^^^^ @function +// <- type.qualifier +// ^ type.qualifier +// ^ keyword.function +// ^ function +// ^ punctuation.bracket +// ^ punctuation.bracket +// ^ operator +// ^ type +// ^ operator +// ^ namespace +// ^ function pub external fn inspect(a) -> a = "Elixir.IO" "inspect" -// <- @keyword.modifier -// ^^^^^^^^ @keyword.modifier -// ^^ @keyword.function -// ^^^^^^^ @function -// ^ @punctuation.bracket -// ^ @type -// ^ @punctuation.bracket -// ^^ @punctuation.delimiter -// ^ @type -// ^ @operator -// ^^^^^^^^^^^ @module -// ^^^^^^^^^ @function +// <- type.qualifier +// ^ type.qualifier +// ^ keyword.function +// ^ function +// ^ punctuation.bracket +// ^ type +// ^ punctuation.bracket +// ^ operator +// ^ type +// ^ operator +// ^ namespace +// ^ function diff --git a/tests/query/highlights/gleam/import.gleam b/tests/query/highlights/gleam/import.gleam index ac452d157..28356ca8c 100644 --- a/tests/query/highlights/gleam/import.gleam +++ b/tests/query/highlights/gleam/import.gleam @@ -1,22 +1,22 @@ import gleam/io -// <- @keyword.import -// ^ @module -// ^ @operator -// ^ @module +// <- include +// ^ namespace +// ^ namespace +// ^ namespace import cat as kitten -// <- @keyword.import -// ^ @module -// ^ @keyword -// ^ @module +// <- include +// ^ namespace +// ^ keyword +// ^ namespace import animal/cat.{Cat, stroke} -// <- @keyword.import -// ^ @module -// ^ @operator -// ^ @punctuation.delimiter -// ^ @punctuation.bracket -// ^^^ @type -// ^ @punctuation.delimiter -// ^^^^^^ @function -// ^ @punctuation.bracket +// <- include +// ^ namespace +// ^ namespace +// ^ punctuation.delimiter +// ^ punctuation.bracket +// ^ type +// ^ punctuation.delimiter +// ^ function +// ^ punctuation.bracket diff --git a/tests/query/highlights/gleam/pipe.gleam b/tests/query/highlights/gleam/pipe.gleam index c696b0227..33f27312b 100644 --- a/tests/query/highlights/gleam/pipe.gleam +++ b/tests/query/highlights/gleam/pipe.gleam @@ -1,18 +1,18 @@ pub fn run() { 1 - // <- @number + // <- number |> add(_, 2) - // <- @operator - // ^^^ @function.call - // ^ @punctuation.bracket - // ^ @comment - // ^ @punctuation.delimiter - // ^ @number - // ^ @punctuation.bracket + // <- operator + // ^ function + // ^ punctuation.bracket + // ^ comment + // ^ punctuation.delimiter + // ^ number + // ^ punctuation.bracket |> add(3) - // <- @operator - // ^^^ @function.call - // ^ @punctuation.bracket - // ^ @number - // ^ @punctuation.bracket + // <- operator + // ^ function + // ^ punctuation.bracket + // ^ number + // ^ punctuation.bracket } diff --git a/tests/query/highlights/gleam/todo.gleam b/tests/query/highlights/gleam/todo.gleam index b7384ecbd..27038bb73 100644 --- a/tests/query/highlights/gleam/todo.gleam +++ b/tests/query/highlights/gleam/todo.gleam @@ -1,7 +1,7 @@ fn favourite_number() -> Int { todo("We're going to decide which number is best tomorrow") - // <- @keyword - // ^ @punctuation.bracket - // ^ @string - // ^ @punctuation.bracket + // <- keyword + // ^ punctuation.bracket + // ^ string + // ^ punctuation.bracket } diff --git a/tests/query/highlights/gleam/try.gleam b/tests/query/highlights/gleam/try.gleam new file mode 100644 index 000000000..136d44eb4 --- /dev/null +++ b/tests/query/highlights/gleam/try.gleam @@ -0,0 +1,11 @@ +pub fn main() { + try x = Ok(1) + // <- keyword + // ^ variable + // ^ operator + // ^ type + // ^ punctuation.bracket + // ^ number + // ^ punctuation.bracket + Ok(x + 1) +} diff --git a/tests/query/highlights/gleam/type.gleam b/tests/query/highlights/gleam/type.gleam index 5b0aa021f..d25efde34 100644 --- a/tests/query/highlights/gleam/type.gleam +++ b/tests/query/highlights/gleam/type.gleam @@ -1,84 +1,83 @@ pub type Cat { -// <- @keyword.modifier -// ^^^^ @keyword.type -// ^^^ @type -// ^ @punctuation.bracket +// <- type.qualifier +// ^ keyword.function +// ^ type +// ^ punctuation.bracket Cat(name: String, cuteness: Int) - // <- @constructor - // ^ @punctuation.bracket - // ^^^^ @variable.member - // ^ @punctuation.delimiter - // ^^^^^^ @type - // ^ @punctuation.delimiter - // ^^^^^^^^ @variable.member - // ^ @punctuation.delimiter - // ^^^ @type - // ^ @punctuation.bracket + // <- type + // ^ punctuation.bracket + // ^ property + // ^ property + // ^ type + // ^ punctuation.delimiter + // ^ property + // ^ property + // ^ type + // ^ punctuation.bracket } fn cats() { Cat(name: "Nubi", cuteness: 2001) - // <- @type - // ^ @punctuation.bracket - // ^^^^ @variable.member - // ^ @punctuation.delimiter - // ^^^^^^ @string - // ^ @punctuation.delimiter - // ^^^^^^^^ @variable.member - // ^ @punctuation.delimiter - // ^^^^ @number - // ^ @punctuation.bracket + // <- type + // ^ punctuation.bracket + // ^ property + // ^ property + // ^ string + // ^ punctuation.delimiter + // ^ property + // ^ property + // ^ number Cat("Ginny", 1950) - // <- @constructor - // ^ @punctuation.bracket - // ^^^^^^^ @string - // ^ @punctuation.delimiter - // ^^^^ @number - // ^ @punctuation.bracket + // <- type + // ^ punctuation.bracket + // ^ string + // ^ punctuation.delimiter + // ^ number + // ^ punctuation.bracket } type Box(inner_type) { -// <- @keyword.type -// ^^^ @type -// ^ @punctuation.bracket -// ^^^^^^^^^^ @type -// ^ @punctuation.bracket -// ^ @punctuation.bracket +// <- keyword.function +// ^ type +// ^ punctuation.bracket +// ^ parameter +// ^ punctuation.bracket +// ^ punctuation.bracket Box(inner: inner_type) - // <- @constructor - // ^ @punctuation.bracket - // ^^^^^ @variable.member - // ^ @punctuation.delimiter - // ^^^^^^^^^^ @type - // ^ @punctuation.bracket + // <- type + // ^ punctuation.bracket + // ^ property + // ^ property + // ^ type + // ^ punctuation.bracket } pub opaque type Counter { -// <- @keyword.modifier -// ^^^^^^ @keyword.modifier -// ^^^^ @keyword.type -// ^^^^^^^ @type -// ^ @punctuation.bracket +// <- type.qualifier +// ^ type.qualifier +// ^ keyword.function +// ^ type +// ^ punctuation.bracket Counter(value: Int) } pub fn have_birthday(person) { Person(..person, age: person.age + 1, is_happy: True) - // <- @constructor - // ^ @punctuation.bracket - // ^^ @operator - // ^^^^^^ @variable - // ^ @punctuation.delimiter - // ^^^ @variable.member - // ^ @punctuation.delimiter - // ^^^^^^ @variable - // ^ @punctuation.delimiter - // ^^^ @variable.member - // ^ @operator - // ^ @number - // ^ @punctuation.delimiter - // ^^^^^^^^ @variable.member - // ^ @punctuation.delimiter - // ^^^^ @boolean - // ^ @punctuation.bracket + // <- type + // ^ punctuation.bracket + // ^ operator + // ^ variable + // ^ punctuation.delimiter + // ^ property + // ^ property + // ^ variable + // ^ punctuation.delimiter + // ^ property + // ^ operator + // ^ number + // ^ punctuation.delimiter + // ^ property + // ^ property + // ^ boolean + // ^ punctuation.bracket } diff --git a/tests/query/highlights/hack/as-foreach.hack b/tests/query/highlights/hack/as-foreach.hack index 611027131..8969be8fc 100644 --- a/tests/query/highlights/hack/as-foreach.hack +++ b/tests/query/highlights/hack/as-foreach.hack @@ -1,6 +1,6 @@ foreach (($array as vec[]) as $item) {} -// ^ @keyword.repeat -// ^ @type +// ^ repeat +// ^ type # Our expectation test for the code below intentionally includes an ERROR. foreach ($array as vec[] as $item) {} diff --git a/tests/query/highlights/hack/async-functions.hack b/tests/query/highlights/hack/async-functions.hack index 41779d76d..4488c992d 100644 --- a/tests/query/highlights/hack/async-functions.hack +++ b/tests/query/highlights/hack/async-functions.hack @@ -1,8 +1,8 @@ async function func0(): void {} -// ^ @type.builtin +// ^ type.builtin async function func1() {} -// ^ @type.builtin -// ^ @keyword.operator +// ^ type.builtin +// ^ keyword.operator async ($x) ==> $x + 1; diff --git a/tests/query/highlights/hack/attribute-type.hack b/tests/query/highlights/hack/attribute-type.hack index 0bd12df8c..5ab9eaa4b 100644 --- a/tests/query/highlights/hack/attribute-type.hack +++ b/tests/query/highlights/hack/attribute-type.hack @@ -2,13 +2,13 @@ newtype T1 = ?shape( // TODO: ?operator (? not captureable at the moment) ?'int' => int -// ^ @operator +// ^ operator ); <> -// ^ @attribute +// ^ attribute type T2 = (function(T1): string); -// ^ @type +// ^ type // TODO: keyword.function (currently not in AST) <> diff --git a/tests/query/highlights/hack/generics.hack b/tests/query/highlights/hack/generics.hack index 50bd50e34..9582240b9 100644 --- a/tests/query/highlights/hack/generics.hack +++ b/tests/query/highlights/hack/generics.hack @@ -1,24 +1,24 @@ class Box { - // ^ @type - // ^ @type + // ^ type + // ^ type protected T $data; - // ^ @keyword.modifier - // ^ @type + // ^ type.qualifier + // ^ type public function __construct(T $data) { - // ^ @type - // ^ @variable.parameter - // ^ @keyword.function - // ^ @keyword.modifier - // ^ @function.method + // ^ type + // ^ parameter + // ^ keyword.function + // ^ type.qualifier + // ^ method $this->data = $data; } public function getData(): T { - // ^ @function.method - // ^ @keyword.modifier + // ^ method + // ^ type.qualifier return $this->data; - // ^ @operator - // ^ @variable.builtin + // ^ operator + // ^ variable.builtin } } diff --git a/tests/query/highlights/hack/heredoc-dollar.hack b/tests/query/highlights/hack/heredoc-dollar.hack index 8ea247389..8034cc863 100644 --- a/tests/query/highlights/hack/heredoc-dollar.hack +++ b/tests/query/highlights/hack/heredoc-dollar.hack @@ -1,4 +1,4 @@ << int, - // ^ @string + // ^ string "b" => string, - // ^ @type.builtin + // ^ type.builtin ); } diff --git a/tests/query/highlights/hack/use.hack b/tests/query/highlights/hack/use.hack index ab17d1140..d7b7ce784 100644 --- a/tests/query/highlights/hack/use.hack +++ b/tests/query/highlights/hack/use.hack @@ -1,28 +1,28 @@ use const Space\Const\C; -// ^ @keyword -// ^ @constant +// ^ keyword +// ^ constant use function Space\Func\F as E; -// ^ @function -// ^ @function +// ^ function +// ^ function use type Space\Type\T; -// ^ @keyword.type +// ^ keyword use namespace Space\Name\N as M; -// ^ @keyword.type -// ^ @module +// ^ keyword +// ^ namespace use namespace Space\Name2\N2, Space\Nothing\N3 as N8, type Space\Type2\N4,; -// ^ @module -// ^ @type +// ^ namespace +// ^ type use namespace Space\Name\N10\{A as A2, B\}; -// ^ @module -// ^ @module -// ^ @module +// ^ namespace +// ^ namespace +// ^ namespace use namespace Space\Name\{\C, Slash as Forward}; use \What\Is\This\{function A as A2, B, const H\S\L as stdlib, function F}; use type \{kind,}; use Q\B\{kind2,}; -// ^ @module +// ^ namespace use type Q\B\{kind3,}; -// <- @keyword.import +// <- include diff --git a/tests/query/highlights/hack/using.hack b/tests/query/highlights/hack/using.hack index c3a7be153..4452ea962 100644 --- a/tests/query/highlights/hack/using.hack +++ b/tests/query/highlights/hack/using.hack @@ -1,3 +1,3 @@ using ($new = new Object(), $file = new File('using', '+using')) {} -// <- @keyword -// ^ @type +// <- keyword +// ^ type diff --git a/tests/query/highlights/hack/xhp.hack b/tests/query/highlights/hack/xhp.hack index 57563a131..992296b97 100644 --- a/tests/query/highlights/hack/xhp.hack +++ b/tests/query/highlights/hack/xhp.hack @@ -4,7 +4,7 @@ echo "Hello $user_name"; // XHP: Typechecked, well-formed, and secure $user_name = 'Andrew'; $xhp = Hello {$user_name}; -// ^ @tag -// ^ @tag -// ^ @string +// ^ tag +// ^ tag +// ^ string echo await $xhp->toStringAsync(); diff --git a/tests/query/highlights/haskell/test.hs b/tests/query/highlights/haskell/test.hs deleted file mode 100644 index f719981ff..000000000 --- a/tests/query/highlights/haskell/test.hs +++ /dev/null @@ -1,343 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} --- ^ @keyword.directive - -{-| Main module -} - -- ^ @comment.documentation -module Main --- ^ @keyword.import - -- ^ @module - ( main - -- ^ @variable - ) where - -- ^ @keyword - -import Prelude hiding (show) --- ^ @keyword.import - -- ^ @module - -- ^ @keyword - -- ^ @variable -import Data.Map (fromList) - -- ^ @module -import qualified Data.Map as Map - -- ^ @module - -- ^ @module -import qualified Chronos - -- ^ @module -import qualified Chronos as C - -- ^ @module - -- ^ @module -import FooMod (BarTy (barField)) - -- ^ @variable.member - -x = mempty { field = 5 } - -- ^ @variable.member - -data ADT --- ^ @keyword - = A Int - -- ^ @constructor - -- ^ @type - | B - -- ^ @constructor - deriving (Eq, Show) - -- ^ @keyword - -- ^ @type - -- ^ @type -mkA x = A x - -- ^ @variable -mkAQualified x = SomeModule.A x - -- ^ @variable - -class Ord a => PartialOrd a - -- ^ @type - -- ^ @variable - -- ^ @type - -- ^ @variable - -instance Ord ADT where - -- ^ @type - -- ^ @type - -newtype Rec --- ^ @keyword - -- ^ @type - = Rec - -- ^ @constructor - { field :: Double - -- ^ @punctuation.bracket - -- ^ @variable.member - -- ^ @type - } - -- ^ @punctuation.bracket - deriving Eq - -- ^ @type -recordWildCard Rec { field } = field - -- ^ @variable.member -recordDotSyntax rec = rec.field - -- ^ @variable.member - - -main :: IO () --- ^ @function - -- ^ @operator - -- ^ @type - -- ^ @type -main = undefined --- ^ @function - -- ^ @keyword.exception - -someFunc0 :: Int -> Int - -- ^ @operator -someFunc0 x = someFunc1 x - -- ^ @variable.parameter - -- ^ @function.call - where - -- ^ @keyword - someFunc1 _ = 5 - -- ^ @function - -- ^ @number -scopedTypeParam (x :: Int) = someFunc x - -- ^ @variable.parameter - -- ^ @type -scopedTypeParam (Just x :: Int) = someFunc x - -- ^ @constructor - -- ^ @variable.parameter - -- ^ @type -scopedTypeParam (f :: Int -> Int) = someFunc x - -- ^ @function - -someInfix :: Integral a => a -> Double - -- ^ @type - -- ^ @variable - -- ^ @operator - -- ^ @variable - -- ^ @type -someInfix x = fromIntegral x `myAdd` floatVal - -- ^ @function.call - -- ^ @variable - -- ^ @operator - -- ^ @variable - where - myAdd :: Num a => a -> a - -- ^ @function - myAdd x y = x + y - -- ^ @variable - -- ^ @variable - floatVal :: Double - -- ^ @variable - floatVal = 5.5 - -- ^ @variable - -- ^ @number.float - intVal :: Int - -- ^ @variable - intVal = getInt 5 - -- ^ @variable - boolVal :: Bool - -- ^ @variable - boolVal = bool False True $ 1 + 2 == 3 - -- ^ @variable - refVal = boolVal - -- ^ @variable - namespacedRecord = NS.Rec { field = bar } - -- ^ @variable - record = Rec { field = bar } - -- ^ @variable - constructorRef = A - -- ^ @function - isInt :: Either Double Int -> Bool - -- ^ @function - isInt eith@Left{} = False - -- ^ @variable.parameter - isInt eith@(Left x) = False - -- ^ @function - -- ^ @variable.parameter - isInt (Left x) = False - -- ^ @variable.parameter - isInt (Right _) = True - -- ^ @function - -someIOaction :: IO () --- ^ @function -anotherIOaction :: IO () -anotherIOaction = do --- ^ @function - -- ^ @keyword - foo <- SomeModule.someFun <$> getArgs --- ^ @variable - -- ^ @module - -- ^ @function.call - -- ^ @operator - _ <- someFunc0 =<< someIOAction - -- ^ @function.call - let bar = SomeModule.doSomething $ "a" "b" - -- ^ @variable - -- ^ @module - -- ^ @function.call - -- ^ @operator - func x y = x + y - 7 - -- ^ @function - -- ^ @variable.parameter - -- ^ @variable - -- ^ @variable - gunc x y = func x $ y + 7 - -- ^ @variable - -- ^ @variable - valueFromList = HashSet.fromList [] - -- ^ @variable - when foo $ putStrLn $ T.showt =<< bar - -- ^ @function.call - -- ^ @variable - -- ^ @function.call - -- ^ @function.call - - pure $ func 1 2 - -- ^ @function.call - -- ^ @function.call - -intVal :: Int -intVal = 5 --- ^ @variable - -intFun :: Int -> Int -intFun = 5 --- ^ @function - -undefinedFun :: Int -> Int -undefinedFun = undefined --- ^ @function - -mbInt :: Maybe Int --- ^ @variable -mbInt = Just 5 --- ^ @variable - -tupleVal :: (a, b) --- ^@variable -tupleVal = (1, "x") --- ^@variable - -listVal :: [a] --- ^@variable -listVal = [1, 2] --- ^@variable --- ^@variable -condVal = if otherwise --- ^@variable - then False - else True - -getLambda x = \y -> x `SomeModule.someInfix` y - -- ^ @variable.parameter - -- ^ @module - -- ^ @operator -lambdaTyped = \(y :: Int) -> x - -- ^ @variable.parameter -lambdaPattern = \(Just x) -> x - -- ^ @variable.parameter -lambdaPatternTyped = \(Just x :: Int) -> x - -- ^ @variable.parameter - -isVowel = (`elem` "AEIOU") - -- ^ @operator -isVowelQualified = (`SomeModule.elem` "AEIOU") - -- ^ @module - -- ^ @operator - -hasVowels = ("AEIOU" `elem`) - -- ^ @operator -hasVowelsQualified = ("AEIOU" `SomeModule.elem`) - -- ^ @module - -- ^ @operator - -quasiQuotedString = [qq|Some string|] --- ^ @variable - -- ^ @function.call - -- ^ @string -quasiQuotedString2 = [SomeModule.qq|Some string|] - -- ^ @module - -- ^ @function.call - -composition f g = f . g - -- ^ @function - -- ^ @function -qualifiedComposition = SomeModule.f . SomeModule.g - -- ^ @function - -- ^ @function -takeMVarOrThrow = evaluate <=< takeMVar - -- ^ @function - -- ^ @function -modifyMVarOrThrow v f = modifyMVar v $ f >=> evaluate - -- ^ @variable - -- ^ @function - -- ^ @function -assertNonEmpty xs = xs `shouldSatisfy` not . null - -- ^ @variable - -- ^ @function - -- ^ @function -appliedComposition f g var = (f . g) var - -- ^ @function.call - -- ^ @function.call -appliedComposition f g var = (NS.f . NS.g) var - -- ^ @function.call - -- ^ @function.call -param1 |*| param2 = Qu $ param1 * param2 --- ^ @variable.parameter - -- ^ @variable.parameter -(param1 :: Int) |*| (param2 :: Int) = Qu $ param1 * param2 --- ^ @variable.parameter - -- ^ @variable.parameter -(Qu a) |/| (SomeModule.Qu b) = a / b - -- ^ @variable.parameter - -- ^ @variable.parameter -(Qu a :: Int) |/| (SomeModule.Qu b :: Int) = a / b - -- ^ @variable.parameter - -- ^ @variable.parameter -(Qu a, b, c :: Int) |/| x = undefined - -- ^ @variable.parameter - -- ^ @variable.parameter - -- ^ @variable.parameter -[Qu a, b, c :: Int] >< x = undefined - -- ^ @variable.parameter - -- ^ @variable.parameter - -- ^ @variable.parameter -listParam [a, b :: Int, Just c] = undefined - -- ^ @variable.parameter - -- ^ @variable.parameter - -- ^ @variable.parameter -tupleParam (a :: Int, b, Just c) = undefined - -- ^ @variable.parameter - -- ^ @variable.parameter - -- ^ @variable.parameter -listLambda = \[a, a :: Int, Just c] -> undefined - -- ^ @variable.parameter - -- ^ @variable.parameter - -- ^ @variable.parameter -tupleLambda = \(a, b :: Int, Just c) -> undefined - -- ^ @variable.parameter - -- ^ @variable.parameter -nestedDestructure (Left (Just a)) = undefined - -- ^ @variable.parameter -typeApplication x y = someFun @ty x y - -- ^ @variable - -- ^ @variable -encrypt key pass = encrypt (defaultOAEPParams SHA1) key pass - -- ^ @variable - -- ^ @variable -recordUpdate x y rec = someFun rec {field = 5} (x, x) y - -- ^ @variable - -- ^ @variable -viewPattern (func -> var) = 5 - -- ^ @function.call - -- ^ @variable.parameter -g (func :: a -> b) x = func y - -- ^ @variable.parameter - -- ^ @function -lambdaAlias :: LambdaAlias -lambdaAlias _ _ _ = undefined - -- ^ @function -spec :: Spec -spec = describe "test ns" $ it "test case" pending --- ^ @variable - -composed = f . g --- ^ @function diff --git a/tests/query/highlights/hocon/test.conf b/tests/query/highlights/hocon/test.conf index 55f4c03e7..881417b67 100644 --- a/tests/query/highlights/hocon/test.conf +++ b/tests/query/highlights/hocon/test.conf @@ -1,59 +1,59 @@ HOCON = Human-Optimized Config Object Notation -// ^ @variable.member -// ^ @string -// ^ @string -// ^ @string -// ^ @string +// ^field +// ^string +// ^string +// ^string +// ^string "it's": "a JSON\nsuperset", -// ^ @string -// ^ @string.escape -// ^ @punctuation.delimiter +// ^string +// ^string.escape +// ^punctuation.delimiter features: [ -// ^ @operator -// ^ @punctuation.bracket +// ^operator +// ^punctuation.bracket less noisy / less pedantic syntax -// ^ @string +// ^string ability to refer to another part of the configuration import/include another configuration file into the current file a mapping to a flat properties list such as Java's system properties ability to get values from environment variables # ability to write comments -// ^@ comment -// ^ @comment +// ^comment +// ^comment // this is also a comment -// ^ @comment -// ^ @comment +// ^comment +// ^comment ] specs url: "https://github.com/lightbend/config/blob/master/HOCON.md" includes: { include required(file("~/prog/tree-sitter-hocon/grammar.js")) -// ^ @keyword -//^ @keyword.import -// ^ @punctuation.bracket -// ^ @punctuation.bracket +// ^keyword +//^include +// ^punctuation.bracket +// ^punctuation.bracket override = true -// ^ @boolean +// ^boolean } it's: ${it's}. A ${HOCON} -// ^ @punctuation.special -// ^ @punctuation.special -// ^ @punctuation.special -// ^ @string -// ^ @string -// ^ @punctuation.special -// ^ @punctuation.special +// ^punctuation.special +// ^punctuation.special +// ^punctuation.special +// ^string +// ^string +// ^punctuation.special +// ^punctuation.special this.is.a."long.key" = null, -// ^ @punctuation.delimiter -// ^ @punctuation.delimiter -// ^ @punctuation.delimiter -// ^ @constant.builtin +// ^punctuation.delimiter +// ^punctuation.delimiter +// ^punctuation.delimiter +// ^constant.builtin week = 7 days -// ^ @number -// ^ @keyword +// ^number +// ^keyword diff --git a/tests/query/highlights/http/test.http b/tests/query/highlights/http/test.http deleted file mode 100644 index 00fca50ab..000000000 --- a/tests/query/highlights/http/test.http +++ /dev/null @@ -1,33 +0,0 @@ -@ENDPOINT=http://localhost:8080/api -# <- @character.special -# ^^^^^^^ @variable -# ^ @operator -# ^^^^^^^^^^^^^^^^^^^^^^^^^ @string - -### GET USERS -GET {{ENDPOINT}}/users HTTP/1.1 -# ^^ @punctuation.bracket -# ^^^^^^^^ @variable -# ^^ @punctuation.bracket -# ^^^^^^ @string.special.url -# ^^^^^^^^ @string.special - -### GET USERS by Offset -GET {{ENDPOINT}}/users?offset=30 HTTP/1.1 -# <- @function.method - -### POST login -POST {{ENDPOINT}}/auth/login HTTP/1.1 -Content-Type: application/json - -{ - "username": "admin", - "password": "password" -} - -### Log Out -POST {{ENDPOINT}}/auth/logout HTTP/1.1 -Content-Type: application/json -# ^^^^^^^^^^ @constant -# ^ @punctuation.delimiter -# vim: ft=http diff --git a/tests/query/highlights/jinja/filters.jinja b/tests/query/highlights/jinja/filters.jinja deleted file mode 100644 index a084cdc1a..000000000 --- a/tests/query/highlights/jinja/filters.jinja +++ /dev/null @@ -1,19 +0,0 @@ -{{ name|striptags|title }} -{# ^^^^ @variable #} -{# ^^^^^ @function.call #} -{# ^^^^^ @function.call #} - -{{ listx|join(', ') }} -{# ^^^^^ @variable #} -{# ^^^^ @function.call #} -{# ^^^^ @string #} - -{{ listx|join(str) }} -{# ^^^^^ @variable #} -{# ^^^^ @function.call #} -{# ^^^ @variable.parameter #} - -{{ foo.bar|random }} -{# ^^^ @variable #} -{# ^^^ @variable.member #} -{# ^^^^^^ @function.call #} diff --git a/tests/query/highlights/jinja/tests.jinja b/tests/query/highlights/jinja/tests.jinja deleted file mode 100644 index 0a138fb80..000000000 --- a/tests/query/highlights/jinja/tests.jinja +++ /dev/null @@ -1,13 +0,0 @@ -{% if loop.index is divisibleby 3 %} -{# ^^^^ @variable #} -{# ^^^^^ @variable.member #} -{# ^^^^^^^^^^ @keyword.operator #} - -{% if loop.index is divisibleby(3) %} -{# ^^^^ @variable #} -{# ^^^^^ @variable.member #} - -{% if foo.bar.baz is divisibleby 3 %} -{# ^^^ @variable #} -{# ^^^ @variable.member #} -{# ^^^ @variable.member #} diff --git a/tests/query/highlights/jinja/variables.jinja b/tests/query/highlights/jinja/variables.jinja deleted file mode 100644 index 1ab78c35a..000000000 --- a/tests/query/highlights/jinja/variables.jinja +++ /dev/null @@ -1,21 +0,0 @@ -{{ foo }} -{# ^^^ @variable #} - -{{ foo.bar }} -{# ^^^ @variable #} -{# ^^^ @variable.member #} - -{{ foo['bar'] }} -{# ^^^ @variable #} -{# ^^^^^ @string #} - -{{ foo.bar.baz }} -{# ^^^ @variable #} -{# ^^^ @variable.member #} -{# ^^^ @variable.member #} - -{{ foo.bar + baz.qux }} -{# ^^^ @variable #} -{# ^^^ @variable.member #} -{# ^^^ @variable #} -{# ^^^ @variable.member #} diff --git a/tests/query/highlights/julia/test.jl b/tests/query/highlights/julia/test.jl deleted file mode 100644 index 338b7f8a1..000000000 --- a/tests/query/highlights/julia/test.jl +++ /dev/null @@ -1,26 +0,0 @@ -function load_data(::Symbol; ::Int) :: Tuple -# <- @keyword.function -# ^ @function.call -# ^ @punctuation.bracket -# ^^ @operator -# ^ @type.builtin -# ^ @punctuation.delimiter -# ^^ @operator -# ^^^ @type.builtin -# ^ @punctuation.bracket -# ^^ @operator -# ^ @type.builtin - dataset = CIFAR10(; Tx = Float32, split = split) -# ^^^^^^^ @variable -# ^ @operator -# ^ @function.call -# ^ @operator -# ^ @type.builtin - X = reshape(dataset.features[:, :, :, begin:n_obs], :, n_obs) # flattening the image pixels -# ^^^^^ @variable.builtin - y = categorical2onehot(dataset.targets[begin:n_obs], N_LABELS) -# ^^^^^ @variable.builtin - return X, y -# ^^^^^^ @keyword.return -end -# <- @keyword.function diff --git a/tests/query/highlights/kos/test.kos b/tests/query/highlights/kos/test.kos deleted file mode 100644 index 4e1b0ec6d..000000000 --- a/tests/query/highlights/kos/test.kos +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env kos -# ^ keyword.directive -public var item = 1; -# ^ keyword -# ^ keyword -# ^ variable -# ^ operator -# ^ number -# ^ punctuation.delimiter - -# hash comment -# <- @comment @spell - -// slash comment -# <- @comment @spell - -/* block comment */ -# <- @comment @spell - -fun name(arg1, -# ^ keyword.function -# ^ function -# ^ punctuation.bracket -# ^ variable.parameter -# ^ punctuation.delimiter - arg2 = "default", -# ^ variable.parameter -# ^ operator -# ^ string -# ^ punctuation.delimiter - arg3...) -# ^ variable.parameter -# ^ operator -# ^ punctuation.bracket -{ -# <- punctuation.bracket - arg1 += 1 - # ^ variable - # ^ operator - # ^ number - arg1 -= 2 - # ^ variable - # ^ operator - # ^ number - arg1 *= 3 - # ^ variable - # ^ operator - # ^ number - arg1 /= 4 - # ^ variable - # ^ operator - # ^ number - arg1 %= 5 - # ^ variable - # ^ operator - # ^ number - arg1 |= 6 - # ^ variable - # ^ operator - # ^ number - arg1 &= 7 - # ^ variable - # ^ operator - # ^ number - arg1 ^= 8 - # ^ variable - # ^ operator - # ^ number - arg1 <<= 9 - # ^ variable - # ^ operator - # ^ number - arg1 >>= 10 - # ^ variable - # ^ operator - # ^ number - arg1 >>>= 11 - # ^ variable - # ^ operator - # ^ number - arg1.prop[arg1](arg1)[void] = true - # ^ variable - # ^ punctuation.delimiter - # ^ property - # ^ punctuation.bracket - # ^ variable - # ^ punctuation.bracket - # ^ punctuation.bracket - # ^ variable - # ^ punctuation.bracket - # ^ punctuation.bracket - # ^ constant.builtin - # ^ operator - # ^ boolean - arg1 = 1 * (arg1 + 2) / arg1 - 3 % arg1 - # ^ variable - # ^ operator - # ^ number - # ^ operator - # ^ punctuation.bracket - # ^ variable - # ^ operator - # ^ number - # ^ punctuation.bracket - # ^ operator - # ^ variable - # ^ operator - # ^ number - # ^ operator - # ^ variable - for const elem in arg1 { - # ^ keyword.repeat - # ^ keyword - # ^ variable - # ^ keyword.repeat - # ^ variable - # ^ punctuation.bracket - if elem { - # ^ keyword.conditional - # ^ variable - # ^ punctuation.bracket - continue - # ^ keyword.repeat - } - # ^ punctuation.bracket - else { - # ^ keyword.conditional - # ^ punctuation.bracket - break - # ^ keyword.repeat - } - # ^ punctuation.bracket - } - # <- punctuation.bracket -} -# <- punctuation.bracket - -name(42) -# <- function.call -# ^ punctuation.bracket -# ^ number -# ^ punctuation.bracket - -name.name() -# <- variable -# ^ punctuation.delimiter -# ^ function.method.call -# ^ punctuation.bracket -# ^ punctuation.bracket - -print("hello \(123 + var) world \(true)") -# <- function.call -# ^ punctuation.bracket -# ^ string -# ^ punctuation.special -# ^ number -# ^ operator -# ^ variable -# ^ punctuation.special -# ^ string -# ^ punctuation.special -# ^ boolean -# ^ punctuation.special -# ^ punctuation.bracket - -[] -> each((x,_,y) => x + y) -# <- punctuation.bracket -#^ punctuation.bracket -# ^ operator -# ^ function.call -# ^ punctuation.bracket -# ^ punctuation.bracket -# ^ variable.parameter -# ^ punctuation.delimiter -# ^ character.special -# ^ punctuation.delimiter -# ^ variable.parameter -# ^ punctuation.bracket -# ^ keyword.function -# ^ variable -# ^ operator -# ^ variable -# ^ punctuation.bracket diff --git a/tests/query/highlights/latex/test.tex b/tests/query/highlights/latex/test.tex deleted file mode 100644 index 9e65b900a..000000000 --- a/tests/query/highlights/latex/test.tex +++ /dev/null @@ -1,33 +0,0 @@ -% vim:ft=latex -% !TeX -% ^ @keyword.directive -%& filename -% ^ @keyword.directive - \begin{equation} \frac{4}{2} + 128 \text{hello} \sum_{n=1}^{\text{hi\_hi\^hi}} n \end{equation} -% ^ @markup.math ^ @none ^ @function - -\begin{equation} - a = b % Comment here -% ^ @comment -% ^ @markup.math -\end{equation} -\begin{equation} - a = b % Comment here -% ^ @comment - b = c -\end{equation} -\text{ -hi $here$ is some text % with a comment -% ^ @comment -% ^ @markup.math -} -\textbf{ -here is some text $5 + 2$ % with a comment -% ^ @comment -% ^ @markup.math -} -\textit{ -here is some text $5 + 2$ % with a comment -% ^ @comment -% ^ @markup.math -} diff --git a/tests/query/highlights/lua/test.lua b/tests/query/highlights/lua/test.lua index 2261d2e4e..efb9a9994 100644 --- a/tests/query/highlights/lua/test.lua +++ b/tests/query/highlights/lua/test.lua @@ -1,18 +1,13 @@ --- luacheck: ignore local a = { 1, 2, 3, 4, 5 } --- ^ @number ^ @punctuation.bracket --- ^ @variable +-- ^ number ^ punctuation.bracket +-- ^ variable local _ = next(a) --- ^ @function.builtin --- ^ @keyword +-- ^ function.builtin +-- ^ keyword _ = next(a) --- ^ @function.builtin +-- ^ function.builtin next(a) --- ^ @function.builtin - --- Checking for incorrect hlgroup of injected luap -string.match(s, '\0%d[^\n]+') --- ^ !constant +-- ^ function.builtin diff --git a/tests/query/highlights/markdown/test.md b/tests/query/highlights/markdown/test.md index 01acfcc19..9423d3e85 100644 --- a/tests/query/highlights/markdown/test.md +++ b/tests/query/highlights/markdown/test.md @@ -1,28 +1,28 @@ # H1 - + ## H2 - + - Item 1 - Item 2 - + 1. Item 1 2. Item 2 - + ----![image_description](https://example.com/image.jpg "awesome image title") - - - - - - + + + + + + [link_text](#local_reference "link go brr...") - - - - - + + + + + diff --git a/tests/query/highlights/nix/test.nix b/tests/query/highlights/nix/test.nix deleted file mode 100644 index 296a5a934..000000000 --- a/tests/query/highlights/nix/test.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - func1 = param: builtins.readFile param; - # ^ @function - # ^ @variable.parameter - # ^ @constant.builtin - # ^ @function.builtin - func2 = { p1, p2 }: p2; - # ^ @function - # ^ @variable.parameter - readFile' = readFile; - # ^ @function.builtin - x = func1 ./path/to/file.nix; -# ^ @variable.member - # ^ @function.call - # ^ @string.special.path - hi = if true then 9 else throw "an error ${here + "string"}"; - # ^ @keyword.exception - # ^ @string - # ^ @variable - # ^ @string -} diff --git a/tests/query/highlights/pascal/test.pas b/tests/query/highlights/pascal/test.pas index 3a6cc786a..f60e8b40b 100644 --- a/tests/query/highlights/pascal/test.pas +++ b/tests/query/highlights/pascal/test.pas @@ -1,39 +1,39 @@ program foobar; -// ^ @keyword +// ^ keyword var -// <- @keyword +// <- keyword foo: bar; -// ^ @variable -// ^ @type +// ^ variable +// ^ type foo: foo.bar; -// ^ @variable -// ^ @type -// ^ @type -// ^ @type +// ^ variable +// ^ type +// ^ type +// ^ type begin -// ^ @keyword +// ^ keyword foo := bar; -// ^ @variable -// ^ @variable +// ^ variable +// ^ variable foo; -// ^ @function +// ^ function foo(); -// ^ @function +// ^ function foo(bar(xyz)); -// ^ @function -// ^ @function -// ^ @variable +// ^ function +// ^ function +// ^ variable xx + yy; -// ^ @variable -// ^ @variable +// ^ variable +// ^ variable xx := y + z + func(a, b, c); -// ^ @variable -// ^ @variable -// ^ @variable -// ^ @function -// ^ @variable -// ^ @variable -// ^ @variable +// ^ variable +// ^ variable +// ^ variable +// ^ function +// ^ variable +// ^ variable +// ^ variable end. -// <- @keyword +// <- keyword diff --git a/tests/query/highlights/php/keywords.php b/tests/query/highlights/php/keywords.php deleted file mode 100644 index 21d248e69..000000000 --- a/tests/query/highlights/php/keywords.php +++ /dev/null @@ -1,82 +0,0 @@ -foo(); -// ^^^^ @variable.builtin -// ^^^ @function.method.call - self::foo(); -// ^^^^ @variable.builtin -// ^^^ @function.call - static::foo(); -// ^^^^^^ @variable.builtin - parent::foo(); -// ^^^^^^ @variable.builtin - $this->foo; -// ^^^ @variable.member - $this->foo(a: 5); -// ^ @variable.parameter - A::$foo::$bar; -// ^^^ @variable.member -// ^^^ @variable.member - } -} diff --git a/tests/query/highlights/prisma/test.prisma b/tests/query/highlights/prisma/test.prisma index 5517e9eb5..9e185cfb5 100644 --- a/tests/query/highlights/prisma/test.prisma +++ b/tests/query/highlights/prisma/test.prisma @@ -47,17 +47,10 @@ model Reaction { } enum ReactionType { -// ^ keyword.type +// ^ keyword LIKE HAHA SAD ANGRY // ^ constant } - -view ReactionView { -// ^ keyword - id Int @unique - postId Int - userId String -} diff --git a/tests/query/highlights/promql/regex.promql b/tests/query/highlights/promql/regex.promql deleted file mode 100644 index fa61094a3..000000000 --- a/tests/query/highlights/promql/regex.promql +++ /dev/null @@ -1,10 +0,0 @@ -foo{path=~"^foo$"}[5m] or -# ^ @string.regexp -foo{path!~"[a-zA-Z0-9]{1,3}"}[5m] or -# ^ @string.regexp -foo{path="/api/users/{userId}"}[5m] or -# ^ @string -foo{path!="/api/users/{userId}"}[5m] -# ^ @string - -# vim: ft=promql diff --git a/tests/query/highlights/proto/test.proto b/tests/query/highlights/proto/test.proto deleted file mode 100644 index fdc610782..000000000 --- a/tests/query/highlights/proto/test.proto +++ /dev/null @@ -1,62 +0,0 @@ -syntax = "proto2"; -// ^^^^^^^^ @string.special -package sls.asfd.asfd; -// ^^^ @variable -// ^ @punctuation.delimiter -// ^^^^ @variable.member -// ^ @punctuation.delimiter -// ^^^^ @variable.member -// ^ @punctuation.delimiter - -import "github.com/gogo/protobuf/gogoproto/gogo.proto"; -import "github.com/gogo/protobuf/gogoproto/gogo.proto"; -import "github.com/gogo/protobuf/gogoproto/gogo.proto"; -import "github.com/gogo/protobuf/gogoproto/gogo.proto"; -import "github.com/gogo/protobuf/gogoproto/gogo.proto"; -import "github.com/gogo/protobuf/gogoproto/gogo.proto"; -import "github.com/gogo/protobuf/gogoproto/gogo.proto"; -import "github.com/gogo/protobuf/gogoproto/gogo.proto"; -//<- @keyword.import - -option (gogoproto.sizer_all) = true; -option (gogoproto.marshaler_all) = true; -option (gogoproto.unmarshaler_all.foo) = true; -// ^^^^^^^^^ @variable -// ^^^^^^^^^^^^^^^ @variable.member -// ^ @punctuation.delimiter -// ^^^ @variable.member - -message LogContent -//<- @keyword.type -{ - required string Key = 1; -// ^^^^^^ @type -// ^^^ @property -// ^ @operator -// ^ @number - required string Value = 2; -// ^^^^^^ @type -// ^^^^^ @property - required CustomType Value = 2; -// ^^^^^^^^ @keyword.modifier -// ^^^^^^^^^^ @type - - optional string cgroup_pids_mount = 76 [default = "/sys/fs/cgroup/pids"]; - - optional JsonFormat json_format = 6 [ -// ^^^^^^^^ @keyword.modifier - retention = RETENTION_RUNTIME, -// ^^^^^^^^^^^^^^^^^ @variable -// ^ @punctuation.delimiter - targets = TARGET_TYPE_MESSAGE, -// ^^^^^^^ @property - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_FILE, - edition_defaults = { edition: "2023", value: "ALLOW" } -// ^^^^^^^ @property -// ^ @punctuation.delimiter -// ^ @punctuation.delimiter -// ^ @punctuation.bracket - ]; -} - diff --git a/tests/query/highlights/python/decorators.py b/tests/query/highlights/python/decorators.py deleted file mode 100644 index 278e4e311..000000000 --- a/tests/query/highlights/python/decorators.py +++ /dev/null @@ -1,22 +0,0 @@ -from dataclasses import dataclass - - -@dataclass -#^^^^^^^^^ @attribute -class Data: - _foo: str - - @property -# ^ @attribute -# ^^^^^^^^ @attribute.builtin - def foo(self) -> str: - return self._foo - - -@pytest.mark.filterwarnings("ignore::DeprecationWarning") -#^^^^^^ @variable -# ^^^^ @variable.member -# ^^^^^^^^^^^^^^ @attribute -def test_func(): - pass - diff --git a/tests/query/highlights/python/docstrings.py b/tests/query/highlights/python/docstrings.py deleted file mode 100644 index 02c0a2cc6..000000000 --- a/tests/query/highlights/python/docstrings.py +++ /dev/null @@ -1,121 +0,0 @@ -# Docstrings according to PEP 257 (https://peps.python.org/pep-0257/) -# <- @comment - -"""Module docstring assigned to `__doc__`...""" -# <- @string.documentation -""" -... with an addtional docstring, not part of `__doc__`. -""" -# <- @string.documentation - -""" -Some random docstring in the middle if nowhere... -""" -# <- @string.documentation -""" -... also with not one ... -""" -# <- @string.documentation -""" -... but two addtional docstrings. -""" -# <- @string.documentation - -oneline_string_assignment = "not detected as docstring" -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @string -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^ !@string.documentation -"""Module attribute docstring.""" -# <- @string.documentation - -multiline_string_assignment = """ - also not detected as docstring - """ -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @string -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !@string.documentation - -looks_like_implicit_string_concatenation = "abc" -# ^^^^^ @string -"def" -# <- @string.documentation - -single_line_implicit_string_concatenation = "abc" "def" -# ^^^^^ @string -# ^^^^^ @string -# ^^^^^ !@string.documentation - -multiline_implicit_string_concatenation = ( - "not " - # <- @string - # <- !@string.documentation - "detected " - # <- @string - # <- !@string.documentation - "as docstring, " - # <- @string - # <- !@string.documentation - "either." - # <- @string - # <- !@string.documentation -) - - -class A: - """ - Class docstring, assigned to `__doc__`. - """ - # <- @string.documentation - - """ - Some random docstring again, ... - """ - # <- @string.documentation - """ - ... with an "additional" docstring. Again. - """ - # <- @string.documentation - - foo = "class attribute" - # ^^^^^^^^^^^^^^^^^ @string - # ^^^^^^^^^^^^^^^^^ !@string.documentation - """ - Class attribute docstring, but an attribute - does not have a `__doc__` attribute itself. - """ - # <- @string.documentation - - bar: int - """Class attribute docstring, type annotation only.""" - # <- @string.documentation - - baz: str = "type annotated class attribute" - # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @string - # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !@string.documentation - """Class attribute docstring, type annotation and assignment.""" - # <- @string.documentation - - def __init__(self): - """Method docstring.""" - # <- @string.documentation - - self.quux = "instance attribute" - # ^^^^^^^^^^^^^^^^^^^^ @string - # ^^^^^^^^^^^^^^^^^^^^ !@string.documentation - """Instance attribute docstring.""" - # <- @string.documentation - - -def f(x): - """Function docstring.""" - # <- @string.documentation - """Addtional function docstring.""" - # <- @string.documentation - return x**2 - - -f.a = 1 -"""Function attribute docstring.""" -# <- @string.documentation - - -"Random docstring with single quotes - legal, but far off standard and confusing." -# <- @string.documentation diff --git a/tests/query/highlights/python/fields.py b/tests/query/highlights/python/fields.py deleted file mode 100644 index cbe80cdc2..000000000 --- a/tests/query/highlights/python/fields.py +++ /dev/null @@ -1,24 +0,0 @@ -class Fields: - type: str -# ^^^^ @variable.member - - def __init__(self, type: str, fields: list[int]) -> None: -# ^^^^ @variable.builtin -# ^^^^ @variable.parameter -# ^^^^^^ @variable.parameter -# ^^^ @type.builtin -# ^^^^ @constant.builtin - self.fields = fields -# ^^^^^^ @variable.member - self.type = type # this cannot be highlighted correctly by Treesitter -# ^^^^ @variable.member - self.__dunderfield__ = None -# ^^^^^^^^^^^^^^^ @variable.member - self._FunKyFielD = 0 -# ^^^^^^^^^^^ @variable.member - self.NOT_A_FIELD = "IM NOT A FIELD" -# ^^^^^^^^^^^ @constant - -Fields(type="schema", fields=[0, 1]) -# ^^^^ @variable.parameter -# ^^^^^^ @variable.parameter diff --git a/tests/query/highlights/python/functions.py b/tests/query/highlights/python/functions.py deleted file mode 100644 index 81dedfbae..000000000 --- a/tests/query/highlights/python/functions.py +++ /dev/null @@ -1,21 +0,0 @@ -def func() -> None: ... - -_ = func() -# ^^^^ @function.call - -"{}".format(1) -# ^^^^^^ @function.method.call - -class Foo: - def method(self) -> None: ... -# ^^^^ @variable.builtin - - @classmethod - def clsmethod(cls) -> None: ... -# ^^^ @variable.builtin - -Foo().method() -# ^^^^^^ @function.method.call - -print() -# ^ @function.builtin diff --git a/tests/query/highlights/python/future_import.py b/tests/query/highlights/python/future_import.py index 065eabfe4..7495588a9 100644 --- a/tests/query/highlights/python/future_import.py +++ b/tests/query/highlights/python/future_import.py @@ -1,4 +1,4 @@ from __future__ import print_function -# ^ @keyword.import -# ^ @module.builtin -# ^ @keyword.import +# ^ @include +# ^ @constant.builtin +# ^ @include diff --git a/tests/query/highlights/python/pattern_matching.py b/tests/query/highlights/python/pattern_matching.py index 2762781b0..38622cf4b 100644 --- a/tests/query/highlights/python/pattern_matching.py +++ b/tests/query/highlights/python/pattern_matching.py @@ -1,51 +1,50 @@ match command.split(): -# ^ @keyword.conditional +# ^ conditional case ["quit"]: - # ^ @keyword.conditional + # ^ conditional print("Goodbye!") quit_game() case ["look"]: - # ^ @keyword.conditional + # ^ conditional current_room.describe() case ["get", obj]: - # ^ @keyword.conditional + # ^ conditional character.get(obj, current_room) case ["go", direction]: - # ^ @keyword.conditional + # ^ conditional current_room = current_room.neighbor(direction) # The rest of your commands go here match command.split(): -# ^ @keyword.conditional +# ^ conditional case ["drop", *objects]: - # ^ @keyword.conditional + # ^ conditional for obj in objects: character.drop(obj, current_room) match command.split(): -# ^ @keyword.conditional +# ^ conditional case ["quit"]: ... # Code omitted for brevity case ["go", direction]: pass case ["drop", *objects]: pass case _: print(f"Sorry, I couldn't understand {command!r}") - # ^^ @@function.macro match command.split(): -# ^ @keyword.conditional +# ^ conditional case ["north"] | ["go", "north"]: - # ^ @keyword.conditional + # ^ conditional current_room = current_room.neighbor("north") case ["get", obj] | ["pick", "up", obj] | ["pick", obj, "up"]: - # ^ @keyword.conditional + # ^ conditional pass match = 2 -# ^ @variable +# ^ variable match, a = 2, 3 -# ^ @variable +# ^ variable match: int = secret -# ^ @variable +# ^ variable x, match: str = 2, "hey, what's up?" -# <- @variable -# ^ @variable +# <- variable +# ^ variable diff --git a/tests/query/highlights/python/raise_from.py b/tests/query/highlights/python/raise_from.py index fb30f4252..8a48a222b 100644 --- a/tests/query/highlights/python/raise_from.py +++ b/tests/query/highlights/python/raise_from.py @@ -2,5 +2,5 @@ try: print(1 / 0) except Exception: raise RuntimeError from None - # ^ @keyword.exception - # ^ @keyword.exception + # ^ @exception + # ^ @exception diff --git a/tests/query/highlights/python/regex.py b/tests/query/highlights/python/regex.py deleted file mode 100644 index 385ec7760..000000000 --- a/tests/query/highlights/python/regex.py +++ /dev/null @@ -1,19 +0,0 @@ -import re - -re_test = re.compile(r"^(?P\d{4}) (?P\d) \w\s{,3}$") -# ^ @string.regexp -re_test = re.compile( - # comment - # ^ @comment - r"^(?P\d{4}){1}" - # ^ @string.regexp - # comment - # ^ @comment - r"(?P\d) \w\s{,3}" - # ^ @string.regexp - # comment - # ^ @comment -) -# interpolation -print("foo %s bar %d" % ("arg1", 2)) -# ^ @character diff --git a/tests/query/highlights/python/yield_from.py b/tests/query/highlights/python/yield_from.py index 6ada002c6..2f3238379 100644 --- a/tests/query/highlights/python/yield_from.py +++ b/tests/query/highlights/python/yield_from.py @@ -1,6 +1,6 @@ from foo import bar -# ^ @keyword.import -# ^ @keyword.import +# ^ @include +# ^ @include def generator(): yield from bar(42) # ^ @keyword.return diff --git a/tests/query/highlights/r/test.r b/tests/query/highlights/r/test.r deleted file mode 100644 index 5fa36cc56..000000000 --- a/tests/query/highlights/r/test.r +++ /dev/null @@ -1,47 +0,0 @@ -init <- 1 -# ^ @variable -# ^ @operator -# ^ @number.float - -r"{(\1\2)}" -> `%r%` -# ^ @string -# ^ @operator -# ^ @variable - - -foo <- c(1L, 2L) -# ^ @function.call -# ^ @number - -b <- list(TRUE, FALSE, NA, Inf) -# ^ @boolean -# ^ @boolean -# ^ @constant.builtin -# ^ @constant.builtin - -b <- list(name = "r", version = R.version$major) -# ^ @variable.parameter -# ^ @string -# ^ @operator -# ^ @variable.member - -Lang$new(name = "r")$print() -# ^ @function.method.call - -for(i in 1:10) { -# <- @keyword.repeat -# ^ @keyword.repeat -} - -add <- function(a, b = 1, ...) { -# ^ @keyword.function -# ^ @variable.parameter -# ^ @variable.parameter -# ^ @constant.builtin - return(a + b) -# ^ @keyword.return -} - -base::letters -# ^ @module -# ^ @variable diff --git a/tests/query/highlights/rust/for.rs b/tests/query/highlights/rust/for.rs index e8c085fa3..27f072847 100644 --- a/tests/query/highlights/rust/for.rs +++ b/tests/query/highlights/rust/for.rs @@ -9,7 +9,7 @@ impl Drop for Foo { fn main() { for i in 0..128 { - // <- @keyword.repeat + // <- @repeat println!("{i}"); } } diff --git a/tests/query/highlights/rust/parameters.rs b/tests/query/highlights/rust/parameters.rs deleted file mode 100644 index 171cc5c5d..000000000 --- a/tests/query/highlights/rust/parameters.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub fn func(ref root: &mut Element, ref mut param2: u32) { - // ^^^ @keyword.modifier - // ^^^^ @variable.parameter - // ^^^ @keyword.modifier - // ^^^ @keyword.modifier - // ^^^^^^ @variable.parameter - return; -} diff --git a/tests/query/highlights/rust/super-crate-imports.rs b/tests/query/highlights/rust/super-crate-imports.rs deleted file mode 100644 index 93263098e..000000000 --- a/tests/query/highlights/rust/super-crate-imports.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::a; -// ^ @module -// ^ !keyword -use crate::{b, c}; -// ^ @module -// ^ !keyword -use super::a; -// ^ @module -// ^ !keyword -use super::{b, c}; -// ^ @module -// ^ !keyword diff --git a/tests/query/highlights/smali/baksmali_test_class.smali b/tests/query/highlights/smali/baksmali_test_class.smali deleted file mode 100644 index 1d2a4cb40..000000000 --- a/tests/query/highlights/smali/baksmali_test_class.smali +++ /dev/null @@ -1,261 +0,0 @@ -.class public Lbaksmali/test/class; -# <- @keyword -# ^^^^^^ @keyword.modifier -.super Ljava/lang/Object; -# ^ @character.special -# ^^^^ @type.builtin -# ^ @punctuation.delimiter - -.source "baksmali_test_class.smali" -# <- @keyword.import - -.implements Lsome/interface; -.implements Lsome/other/interface; - - -.annotation build Lsome/annotation; -# ^^^^^ @keyword.modifier -# ^^^^ @type -# ^ @punctuation.delimiter - value1 = "test" -# ^^^^^^ @variable.member -# ^ @operator -# ^^^^^^ @string - value2 = .subannotation Lsome/annotation; - value1 = "test2" - value2 = Lsome/enum; - .end subannotation -.end annotation - -.annotation system Lsome/annotation; -.end annotation - - - -.field public static aStaticFieldWithoutAnInitializer:I -# ^ @punctuation.delimiter -# ^ @type.builtin - -.field public static longStaticField:J = 0x300000000L -# ^^^^^^^^^^^^ @number -.field public static longNegStaticField:J = -0x300000000L - -.field public static intStaticField:I = 0x70000000 -.field public static intNegStaticField:I = -500 - -.field public static shortStaticField:S = 500s -.field public static shortNegStaticField:S = -500s - -.field public static byteStaticField:B = 123t -.field public static byteNegStaticField:B = 0xAAt - -.field public static floatStaticField:F = 3.1415926f -# ^^^^^^^^^^ @number.float - -.field public static doubleStaticField:D = 3.141592653589793 - -.field public static charStaticField:C = 'a' -# ^^^ @character -.field public static charEscapedStaticField:C = '\n' -# ^^ @string.escape - -.field public static boolTrueStaticField:Z = true -# ^^^^ @boolean -.field public static boolFalseStaticField:Z = false - -.field public static typeStaticField:Ljava/lang/Class; = Lbaksmali/test/class; - -.field public static stringStaticField:Ljava/lang/String; = "test" -.field public static stringEscapedStaticField:Ljava/lang/String; = "test\ntest" - - -.field public static fieldStaticField:Ljava/lang/reflect/Field; = Lbaksmali/test/class;->fieldStaticField:Ljava/lang/reflect/Field; - -.field public static methodStaticField:Ljava/lang/reflect/Method; = Lbaksmali/test/class;->testMethod(ILjava/lang/String;)Ljava/lang/String; -# ^^ @punctuation.delimiter -# ^^^^^^^^^^ @function.method.call - -.field public static arrayStaticField:[I = {1, 2, 3, {1, 2, 3, 4}} -# ^ @punctuation.special -# ^ @punctuation.bracket -# ^ @punctuation.delimiter - -.field public static enumStaticField:Lsome/enum; = .enum Lsome/enum;->someEnumValue:Lsome/enum; -# ^^^^^^^^^^^^^ @variable.member - -.field public static annotationStaticField:Lsome/annotation; = .subannotation Lsome/annotation; - value1 = "test" - value2 = .subannotation Lsome/annotation; - value1 = "test2" - value2 = Lsome/enum; - .end subannotation -.end subannotation - -.field public static staticFieldWithAnnotation:I - .annotation runtime La/field/annotation; -# ^^^^^^^ @keyword.modifier - this = "is" - a = "test" - .end annotation - .annotation runtime Lorg/junit/Test; - .end annotation -.end field - -.field public instanceField:Ljava/lang/String; - - - -.method public constructor ()V -# <- @keyword.function -# ^^^^^^^^^^^ @constructor -# ^^^^^^ @constructor - .registers 1 - invoke-direct {p0}, Ljava/lang/Object;->()V -# ^^^^^^^^^^^^^ @keyword.operator -# ^^ @variable.parameter.builtin - return-void -# ^^^^^^^^^^^ @keyword.return -.end method - -.method public testMethod(ILjava/lang/String;)Ljava/lang/String; -# ^^^^^^^^^^ @function.method - .registers 3 - .annotation runtime Lorg/junit/Test; - .end annotation - .annotation system Lyet/another/annotation; - somevalue = 1234 - anothervalue = 3.14159 - .end annotation - - const-string v0, "testing\n123" -# ^^ @variable.builtin - - goto switch: -# ^^^^^^^ @label - - sget v0, Lbaksmali/test/class;->staticField:I - - switch: - packed-switch v0, pswitch: - - try_start: - const/4 v0, 7 - const v0, 10 - nop - try_end: - .catch Ljava/lang/Exception; {try_start: .. try_end:} handler: -# ^^^^^^ @keyword.exception - .catchall {try_start: .. try_end:} handler2: -# ^^^^^^^^^ @keyword.exception -# ^^ @operator - - handler: - - Label10: - Label11: - Label12: - Label13: - return-object v0 - - - - .array-data 4 - 1 2 3 4 5 6 200 - .end array-data - - pswitch: - .packed-switch 10 - Label10: - Label11: - Label12: - Label13: - .end packed-switch - - handler2: - - return-void - -.end method - -.method public abstract testMethod2()V - .annotation runtime Lsome/annotation; - subannotation = .subannotation Lsome/other/annotation; - value = "value" - .end subannotation - .end annotation - .annotation runtime Lorg/junit/Test; - .end annotation -.end method - - -.method public tryTest()V - .registers 1 - - handler: - nop - - - try_start: - const/4 v0, 7 - const v0, 10 - nop - try_end: - .catch Ljava/lang/Exception; {try_start: .. try_end:} handler: -.end method - - -.method public debugTest(IIIII)V - .registers 10 - - .parameter "Blah" - .parameter - .parameter "BlahWithAnnotations" - .annotation runtime Lsome/annotation; - something = "some value" - somethingelse = 1234 - .end annotation - .annotation runtime La/second/annotation; - .end annotation - .end parameter - .parameter - .annotation runtime Lsome/annotation; - something = "some value" - somethingelse = 1234 - .end annotation - .end parameter - .parameter "LastParam" - - .prologue -# ^^^^^^^^^ @keyword - - nop - nop - - .source "somefile.java" -# ^^^^^^^ @keyword.import - .line 101 -# ^^^ @string.special - - nop - - - .line 50 - - .local v0, aNumber:I -# ^^^^^^^ @variable - const v0, 1234 - .end local v0 - - .source "someotherfile.java" - .line 900 - - const-string v0, "1234" - - .restart local v0 - const v0, 6789 - .end local v0 - - .epilogue -# ^^^^^^^^^ @keyword - -.end method diff --git a/tests/query/highlights/solidity/test.sol b/tests/query/highlights/solidity/test.sol index 52334bd7e..a4b642ee6 100644 --- a/tests/query/highlights/solidity/test.sol +++ b/tests/query/highlights/solidity/test.sol @@ -1,27 +1,27 @@ // Example contract from official documentation at https://github.com/ethereum/solidity/blob/v0.8.12/docs/examples/voting.rst // SPDX-License-Identifier: GPL-3.0 -// ^ @comment +// ^ comment pragma solidity >=0.7.0 <0.9.0; -// ^ @keyword.directive -// ^ @keyword.directive +// ^ preproc +// ^ attribute import * as something from "anotherFile"; -// ^ ^ ^ @keyword.import +// ^ ^ ^ include /// @title Voting with delegation. -// <- @comment +// ^ preproc contract Ballot { -// ^keyword.type -// ^ @type +// ^keyword +// ^ type // This declares a new complex type which will // be used for variables later. // It will represent a single voter. struct Voter { -// ^ @type +// ^ type uint weight; // weight is accumulated by delegation -// ^ @type.builtin -// ^ @variable.member +// ^ type +// ^ field bool voted; // if true, that person already voted address delegate; // person delegated to uint vote; // index of the voted proposal @@ -34,23 +34,23 @@ contract Ballot { } address public chairperson; -// ^ @type.builtin +// ^ type // This declares a state variable that // stores a `Voter` struct for each possible address. mapping(address => Voter) public voters; -// ^ ^ @punctuation.bracket -// ^ @punctuation.delimiter +// ^ ^ punctuation.bracket +// ^ punctuation.delimiter // A dynamically-sized array of `Proposal` structs. Proposal[] public proposals; enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill } -// ^ @constant +// ^ constant /// Create a new ballot to choose one of `proposalNames`. constructor(bytes32[] memory proposalNames) { -// ^ @constructor +// ^ constructor chairperson = msg.sender; voters[chairperson].weight = 1; @@ -63,7 +63,7 @@ contract Ballot { // appends it to the end of `proposals`. proposals.push(Proposal({ name: proposalNames[i], -// ^ @variable.member +// ^ field voteCount: 0 })); } @@ -72,9 +72,9 @@ contract Ballot { // Give `voter` the right to vote on this ballot. // May only be called by `chairperson`. function giveRightToVote(address voter) external { -// ^ @keyword.function -// ^ @function -// ^ @variable.parameter +// ^ keyword.function +// ^ function +// ^ parameter // If the first argument of `require` evaluates // to `false`, execution terminates and all // changes to the state and to Ether balances @@ -180,7 +180,7 @@ contract Ballot { contract Another { Ballot b = new Ballot(new bytes32[](1)); -// ^ @keyword.operator +// ^ keyword.operator } // vim:ft=solidity diff --git a/tests/query/highlights/starlark/test.bzl b/tests/query/highlights/starlark/test.bzl deleted file mode 100644 index 88251f615..000000000 --- a/tests/query/highlights/starlark/test.bzl +++ /dev/null @@ -1,11 +0,0 @@ -# split -# ^ @comment -assert_eq('foo bar'.split(' '), ['foo', 'bar']) -# ^ @keyword -# ^ @punctuation.bracket -# ^ @string -# ^ @punctuation.delimiter -assert_eq('foo bar foo'.rsplit(' ', 1), ['foo bar', 'foo']) -# ^ @number -assert_eq("foo %s bar %d" % ("arg1", 2), "foo arg1 bar 2") -# ^ @character diff --git a/tests/query/highlights/t32/comments.cmm b/tests/query/highlights/t32/comments.cmm deleted file mode 100644 index e36f7e63a..000000000 --- a/tests/query/highlights/t32/comments.cmm +++ /dev/null @@ -1,10 +0,0 @@ -// This is a comment -; <- @comment - -; Another comment -; <- @comment - -ECHO &a // This is a trailing comment -; ^ @comment - -// vim: set ft=t32: diff --git a/tests/query/highlights/t32/keywords.cmm b/tests/query/highlights/t32/keywords.cmm deleted file mode 100644 index 22d3c1b63..000000000 --- a/tests/query/highlights/t32/keywords.cmm +++ /dev/null @@ -1,125 +0,0 @@ -PRIVATE &password -; <- @keyword -; ^ @variable.builtin -ENTRY &password -; <- @keyword -; ^ @variable.parameter - -ENTRY %LINE &salt -; <- @keyword -; ^ @constant.builtin -; ^ @variable.parameter - -IF "&password"=="" -; <- @keyword.conditional -; ^ @string -; ^ @variable.builtin -; ^ @operator -( - ECHO "Failed to provide password." - ENDDO -; ^ @keyword.return -) -ELSE -; <- @keyword.conditional -( - PRIVATE &pass - - &pass=FALSE() -; ^ @function.builtin - WHILE !&pass -; ^ @operator - ( - GOSUB verify_password "&password" -; ^ @function.call - RETURNVALUES &pass -; ^ @variable.parameter - WAIT 10.ms -; ^ @number.float - ) - - IF !&pass - GOTO fail -; ^ @label - ELSE IF &debug -; ^ @keyword.conditional -; ^ @keyword.conditional - ( - GOSUB start_debug -; ^ @function.call - ) -) - -LOCAL &num -; ^ @variable.builtin - -&num = 2. -; ^ @number - -RePeaT &num PRINT "Password: &password" -; ^ @variable.builtin -; ^ @variable.builtin - -WinCLEAR -FramePOS ,,,,Maximized -; ^ @punctuation.delimiter -; ^ @constant.builtin -WinPOS 0% 50% 100% 35% -; ^ @number.float -COVerage.ListFunc - -ENDDO - - -fail: -; <- @label - PRINT %ERROR "Password verification failed." - END -; ^ @keyword.return - - -verify_password: -; <- @function -( - PARAMETERS &password -; ^ @variable.parameter - - SYStem.Option.KEYCODE "&password" - SYStem.JtagClock 1kHz -; ^ @number.float - SYStem.Mode.Attach - - Data.Set N: EAXI:0x34000000 %Long 0x34000100 0x34000021 /verify -; ^ @constant.builtin -; ^ @constant.builtin -; ^ @number -; ^ @constant.builtin -; ^ @number -; ^ @constant.builtin - - RETURN TRUE() -; ^ @keyword.return -) - - -SUBROUTINE start_debug -; <- @keyword.function -; ^ @function -( - COVerage.ListModule %MULTI.OBC \sieve -; ^ @keyword -; ^ @constant.builtin -; ^ @variable - - Var.DRAW flags[0..16] /Alternate 3 -; ^ @keyword -; ^ @variable -; ^ @constant.builtin -; ^ @number - - Go main - RETURN -; ^ @keyword.return -) - -// vim: set ft=t32: diff --git a/tests/query/highlights/t32/literals.cmm b/tests/query/highlights/t32/literals.cmm deleted file mode 100644 index 92c9e5b16..000000000 --- a/tests/query/highlights/t32/literals.cmm +++ /dev/null @@ -1,39 +0,0 @@ -WinPOS ,,1000.,,,,myWatchWindow -; ^ @number - -PRinTer.OPEN "~~~/varwatch.txt" ASCIIE -; ^ @string - -sYmbol.NEW _InitialSP 0x34000100 -; ^ @number - -DO ~~~~/test.cmm -; ^ @string.special.path - -WAIT 1.ns -; ^ @number.float - -SYStem.JtagClock 100.GHZ -; ^ @number.float - -DATA.SET P:&HEAD+0x4 %LONG DATA.LONG(EA:&HEAD+0x4)&0xFFFFFF -; ^ @constant.builtin - -List `main` -; ^ @variable - -&range = 'a'--'z'||'0'--'9' -; ^ @character -; ^ @operator -; ^ @character - -Data.Set N: 0xffff800000 0y0011xx01xx&&a -; ^ @constant.builtin -; ^ @number -; ^ @number -; ^ @operator - -WinPOS 0% 85% 100% 15% -; ^ @number.float - -// vim: set ft=t32: diff --git a/tests/query/highlights/t32/var.cmm b/tests/query/highlights/t32/var.cmm deleted file mode 100644 index 2413c61a3..000000000 --- a/tests/query/highlights/t32/var.cmm +++ /dev/null @@ -1,75 +0,0 @@ -Var.NEWGLOBAL char[4][32] \myarr -; <- @keyword -; ^ @type.builtin -; ^ @variable -LOCAL &i &data - -&data="zero|one|two|three" - -&i=0. -WHILE &i<4 -( - PRIVATE &val - &val=STRing.SPLIT("&data","|",&i) - Var.Assign \myarr[&i]="&val" -; ^ @variable -; ^ @operator - &i=&i+1. -) - -Var.NEWLOCAL \x -; <- @keyword -; ^ @variable -Var.set \x=func3(5,3) -; ^ @variable -; ^ @function.call -; ^ @number -PRINT Var.VALUE(\x) -; ^ @variable -PRINT Var.VALUE('a') -; ^ @character -Var.Assign (*ap)[2..4] = &a -; ^ @variable -; ^ @variable -Var.Assign sp = &s.n+offset -; ^ @variable -; ^ @variable -; ^ @variable.member -; ^ @variable -Var.Assign padd = (CAddition const * volatile)&d -; ^ @variable -; ^ @type -; ^ @keyword.modifier -; ^ @keyword.modifier -; ^ @variable -Var.Assign e1 = (enum e2)&e -; ^ @variable -; ^ @keyword.type -; ^ @type -; ^ @variable -Var.Assign *vector = (struct Vector3d*)&acceleration -; ^ @variable -; ^ @keyword.type -; ^ @type -; ^ @variable -Var.Assign z = (union foo)x -; ^ @variable -; ^ @keyword.type -; ^ @type -; ^ @variable -Var.Assign b = -a -; ^ @variable -; ^ @variable -Var.Assign c = i++ -; ^ @variable -; ^ @variable -Var.Assign d = sizeof(int) -; ^ @variable -; ^ @keyword.operator -; ^ @type.builtin -Var.call strcmp(key,buffer) -; ^ @function.call -; ^ @variable -; ^ @variable - -// vim: set ft=t32: diff --git a/tests/query/highlights/tiger/built-ins.tig b/tests/query/highlights/tiger/built-ins.tig index 9aa649421..7cc1ca501 100644 --- a/tests/query/highlights/tiger/built-ins.tig +++ b/tests/query/highlights/tiger/built-ins.tig @@ -1,21 +1,21 @@ let var a := exit(0) - /* ^ @function.builtin */ + /* ^ function.builtin */ primitive exit(ret: int) /* Shadowing the prelude-included built-in */ - /* ^ @type.builtin */ + /* ^ type.builtin */ var b := exit(0) - /* ^ @function.builtin */ + /* ^ function.builtin */ type int = string /* Shadowing the built-in type */ - /* ^ @type.builtin */ + /* ^ type.builtin */ var c : int := "This is an \"int\"" - /* ^ @type.builtin (not sure why it isn't 'type')*/ + /* ^ type.builtin (not sure why it isn't 'type')*/ var d : Object := nil - /* ^ @type.builtin */ + /* ^ type.builtin */ type Object = int @@ -23,22 +23,22 @@ let in let var c : int := "This is an int" - /* ^ @type.builtin (not sure why it isn't 'type')*/ + /* ^ type.builtin (not sure why it isn't 'type')*/ var d : Object := "This is an object" - /* ^ @type.builtin (not sure why it isn't 'type')*/ + /* ^ type.builtin (not sure why it isn't 'type')*/ in end; exit(1); - /* <- @function.builtin */ + /* <- function.builtin */ print("shadowing is fun"); - /* <- @function.builtin */ + /* <- function.builtin */ self; - /* <- @variable.builtin */ + /* <- variable.builtin */ b := print - /* ^ @variable */ + /* ^ variable */ end /* vim: set ft=tiger: */ diff --git a/tests/query/highlights/tiger/comment.tig b/tests/query/highlights/tiger/comment.tig index 9323dba05..a9c91535f 100644 --- a/tests/query/highlights/tiger/comment.tig +++ b/tests/query/highlights/tiger/comment.tig @@ -1,6 +1,6 @@ /* This is /* a nested */ comment */ -/* <- @comment - ^ @comment - ^ @comment +/* <- comment + ^ comment + ^ comment */ /* vim: set ft=tiger: */ diff --git a/tests/query/highlights/tiger/functions.tig b/tests/query/highlights/tiger/functions.tig index 706f1991a..219c05916 100644 --- a/tests/query/highlights/tiger/functions.tig +++ b/tests/query/highlights/tiger/functions.tig @@ -1,9 +1,9 @@ primitive print(s: string) -/* ^ @function */ -/* ^ @variable.parameter */ +/* ^ function */ +/* ^ parameter */ function func(a: int) : int = (print("Hello World!"); a) -/* ^ @function */ -/* ^ @variable.parameter */ -/* ^ @function.builtin */ +/* ^ function */ +/* ^ parameter */ +/* ^ function.builtin */ /* vim: set ft=tiger: */ diff --git a/tests/query/highlights/tiger/identifiers.tig b/tests/query/highlights/tiger/identifiers.tig index 8d2207dd6..4216c930d 100644 --- a/tests/query/highlights/tiger/identifiers.tig +++ b/tests/query/highlights/tiger/identifiers.tig @@ -1,30 +1,30 @@ type int = int -/* ^ @variable */ -/* ^ @type.builtin */ +/* ^ variable */ +/* ^ type.builtin */ type int_array = array of int -/* ^ @type.builtin */ +/* ^ type.builtin */ type record = {a: int, b: string} -/* ^ @variable.member */ -/* ^ @type.builtin */ -/* ^ @variable.member */ -/* ^ @type.builtin */ +/* ^ property */ +/* ^ type.builtin */ +/* ^ property */ +/* ^ type.builtin */ var record := record {a = 12, b = "27"} -/* ^ @variable */ -/* ^ @type */ -/* ^ @variable.member */ -/* ^ @variable.member */ +/* ^ variable */ +/* ^ type */ +/* ^ property */ +/* ^ property */ var array := int_array[12] of 27; -/* ^ @variable */ -/* ^ @type */ +/* ^ variable */ +/* ^ type */ primitive func(a: int, b: string) : array -/* ^ @variable.parameter */ -/* ^ @type.builtin */ -/* ^ @variable.parameter */ -/* ^ @type.builtin */ -/* ^ @type */ +/* ^ parameter */ +/* ^ type.builtin */ +/* ^ parameter */ +/* ^ type.builtin */ +/* ^ type */ /* vim: set ft=tiger: */ diff --git a/tests/query/highlights/tiger/imports.tig b/tests/query/highlights/tiger/imports.tig index 1c7ce308d..068dc4810 100644 --- a/tests/query/highlights/tiger/imports.tig +++ b/tests/query/highlights/tiger/imports.tig @@ -1,4 +1,4 @@ import "lib.tih" -/* <- @keyword.import */ -/* ^ @string.special.path */ +/* <- include */ +/* ^ string.special */ /* vim: set ft=tiger: */ diff --git a/tests/query/highlights/tiger/keywords.tig b/tests/query/highlights/tiger/keywords.tig index c92cd929a..862a531cd 100644 --- a/tests/query/highlights/tiger/keywords.tig +++ b/tests/query/highlights/tiger/keywords.tig @@ -1,42 +1,42 @@ let -/* <- @keyword */ +/* <- keyword */ var a := 12 - /* <- @keyword */ + /* <- keyword */ function f() : int = a - /* <- @keyword.function */ + /* <- keyword.function */ primitive g() - /* <- @keyword.function */ + /* <- keyword.function */ import "lib.tih" - /* <- @keyword.import */ + /* <- include */ type array_of_int = array of int - /* <- @keyword */ - /* ^ @keyword */ - /* ^ @keyword */ + /* <- keyword */ + /* ^ keyword */ + /* ^ keyword */ in -/* <- @keyword */ +/* <- keyword */ 12; if 12 then 27 else 42; - /* <- @keyword */ - /* ^ @keyword */ - /* ^ @keyword */ + /* <- keyword */ + /* ^ keyword */ + /* ^ keyword */ for i := 12 to 27 do 42; - /* <- @keyword.repeat */ - /* ^ @keyword.repeat */ - /* ^ @keyword.repeat */ + /* <- repeat */ + /* ^ repeat */ + /* ^ repeat */ while 12 do break - /* <- @keyword.repeat */ - /* ^ @keyword.repeat */ - /* ^ @keyword */ + /* <- repeat */ + /* ^ repeat */ + /* ^ keyword */ end -/* <- @keyword */ +/* <- keyword */ /* vim: set ft=tiger: */ diff --git a/tests/query/highlights/tiger/literals.tig b/tests/query/highlights/tiger/literals.tig index 46f3c8616..c7d7b5d8e 100644 --- a/tests/query/highlights/tiger/literals.tig +++ b/tests/query/highlights/tiger/literals.tig @@ -1,9 +1,9 @@ nil -/* <- @constant.builtin */ +/* <- constant.builtin */ 42 -/* <- @number */ +/* <- number */ "Hello World!\n" -/* <- @string - ^ @string.escape +/* <- string + ^ string.escape */ /* vim: set ft=tiger: */ diff --git a/tests/query/highlights/tiger/meta-variables.tig b/tests/query/highlights/tiger/meta-variables.tig index 1b2c6c976..24c01ac69 100644 --- a/tests/query/highlights/tiger/meta-variables.tig +++ b/tests/query/highlights/tiger/meta-variables.tig @@ -1,14 +1,14 @@ let _chunks(42) - /* <- @keyword */ + /* <- keyword */ in _lvalue(12) : _namety(42) := _cast("I'm So Meta Even This Acronym", string); - /* <- @keyword */ - /* ^ @keyword */ - /* ^ @keyword */ + /* <- keyword */ + /* ^ keyword */ + /* ^ keyword */ _exp(42) - /* <- @keyword */ + /* <- keyword */ end /* vim: set ft=tiger: */ diff --git a/tests/query/highlights/tiger/object-oriented.tig b/tests/query/highlights/tiger/object-oriented.tig index 5c48c543e..b09b82b19 100644 --- a/tests/query/highlights/tiger/object-oriented.tig +++ b/tests/query/highlights/tiger/object-oriented.tig @@ -1,29 +1,29 @@ let class A extends Object {} - /* <- @keyword.type */ - /* ^ @keyword */ - /* ^ @type.builtin */ + /* <- keyword */ + /* ^ keyword */ + /* ^ type.builtin */ type B = class extends A { - /* ^ @keyword.type */ - /* ^ @keyword */ - /* ^ @type */ + /* ^ keyword */ + /* ^ keyword */ + /* ^ type */ var a := 12 method meth() : int = self.a - /* <- @keyword.function */ - /* ^ @function.method */ - /* ^ @variable.builtin */ + /* <- keyword.function */ + /* ^ method */ + /* ^ variable.builtin */ } var object := new B - /* ^ @keyword.operator */ + /* ^ keyword.operator */ in object.a := 27; - /* ^ @variable.member */ + /* ^ property */ object.meth() - /* ^ @function.method */ + /* ^ method */ end /* vim: set ft=tiger: */ diff --git a/tests/query/highlights/tiger/operators.tig b/tests/query/highlights/tiger/operators.tig index d803af75b..569b8a8bc 100644 --- a/tests/query/highlights/tiger/operators.tig +++ b/tests/query/highlights/tiger/operators.tig @@ -1,49 +1,49 @@ let var a : int := 42 - /* ^ @punctuation.delimiter */ - /* ^ @operator */ + /* ^ punctuation.delimiter */ + /* ^ operator */ in ( - /* <- @punctuation.bracket */ + /* <- punctuation.bracket */ -1 | 2 & 3 + 4 * 5; - /* <- @operator */ - /* ^ @operator */ - /* ^ @operator */ - /* ^ @operator */ - /* ^ @operator */ - /* ^ @punctuation.delimiter */ + /* <- operator */ + /* ^ operator */ + /* ^ operator */ + /* ^ operator */ + /* ^ operator */ + /* ^ punctuation.delimiter */ 12 >= 27; - /* ^ @operator */ + /* ^ operator */ 12 <= 27; - /* ^ @operator */ + /* ^ operator */ 12 = 27; - /* ^ @operator */ + /* ^ operator */ 12 <> 27; - /* ^ @operator */ + /* ^ operator */ 12 < 27; - /* ^ @operator */ + /* ^ operator */ 12 > 27; - /* ^ @operator */ + /* ^ operator */ record.field; - /* ^ @punctuation.delimiter */ + /* ^ punctuation.delimiter */ func(a, b); - /* ^ @punctuation.bracket */ - /* ^ @punctuation.bracket */ - /* ^ @punctuation.delimiter */ + /* ^ punctuation.bracket */ + /* ^ punctuation.bracket */ + /* ^ punctuation.delimiter */ record_type { }; - /* ^ @punctuation.bracket */ - /* ^ @punctuation.bracket */ + /* ^ punctuation.bracket */ + /* ^ punctuation.bracket */ array[42] - /* ^ @punctuation.bracket */ - /* ^ @punctuation.bracket */ + /* ^ punctuation.bracket */ + /* ^ punctuation.bracket */ ) - /* <- @punctuation.bracket */ + /* <- punctuation.bracket */ end /* vim: set ft=tiger: */ diff --git a/tests/query/highlights/typescript/as.ts b/tests/query/highlights/typescript/as.ts index 30be1ffae..b1f1533b4 100644 --- a/tests/query/highlights/typescript/as.ts +++ b/tests/query/highlights/typescript/as.ts @@ -1,8 +1,8 @@ import * as foo from 'foo'; -// ^ @keyword.import +// ^ include export { foo as bar }; -// ^ @keyword.import +// ^ include const n = 5 as number; -// ^ @keyword.operator +// ^ keyword diff --git a/tests/query/highlights/usd/prims.usda b/tests/query/highlights/usd/prims.usda deleted file mode 100644 index dcb6c3b59..000000000 --- a/tests/query/highlights/usd/prims.usda +++ /dev/null @@ -1,120 +0,0 @@ -def Xform "cube" ( - assetInfo = { - # <- @keyword - asset[] payloadAssetDependencies = [@fizz.usd@, @buzz.usd@] - # <- @type - # ^ @punctuation.bracket - # ^ @keyword - # ^ @string.special.url - # ^ @punctuation.delimiter - # ^ @string.special.url - } -) -{ -} - -def "root" ( - add references = @foo.usda@ (offset = 1; scale = 2.0) - # <- @string.special.url - # ^ @string.special - # ^ @keyword - # ^ @number - # ^ @punctuation.delimiter - # ^ @keyword - # ^ @number.float -) -{ -} - -def "World" -{ - over "points" ( - clips = { - # <- @keyword - dictionary default = { - # <- @type - # ^ @variable - double2[] times = [(101, 101), (102, 102)] - # <- @type - # ^ @keyword - # ^ @number - } - } - ) - { - } -} - -def Xform "torch_2" ( - payload = @./torch.usda@ - kind = "model" -) -{ - // Pre-published light list - # <- @comment - rel lightList = [ ] # inline comment - # ^ @comment - token lightList:cacheBehavior = "consumeAndContinue" - - double3 xformOp:translate = (1, 0, 0.5) - uniform token[] xformOpOrder = ["xformOp:translate"] -} - -def "foo" ( - "some comment" - # <- @comment.documentation -) -{ -} - -def "foo" ( - # inline comment - "actual in-description comment" - # <- @comment.documentation -) -{ -} - -def "foo" ( - add references = @foo.usda@ - # <- @function.call - append references = @foo.usda@ - # <- @function.call - delete references = @foo.usda@ - # <- @function.call - reorder references = [@foo.usda@] - # <- @function.call - - references = [@foo.usda@] # explicit -) -{ -} - -over "Parent" ( - prepend references = [, @./ref.usda@] - # <- @function.call - # ^ @keyword - # ^ @string.special - # ^ @string.special.url - # ^ @string.special -) -{ -} - -def "foo" -{ - float value.timeSamples = { - # <- @type - # ^ @variable - # ^ @property - -414: 14.4 - # <- @number - # ^ @number.float - 10: 201.0, - # <- @number - # ^ @number.float - 10.123: 201.0123, - # <- @number.float - # ^ @number.float - } -} diff --git a/tests/query/highlights/usd/properties.usda b/tests/query/highlights/usd/properties.usda deleted file mode 100644 index 790ccfab7..000000000 --- a/tests/query/highlights/usd/properties.usda +++ /dev/null @@ -1,21 +0,0 @@ -dictionary foo = {} -# <- @type -half[] foo = [2, 1, 2] -# <- @type -string foo = "something" -# <- @type -timecode time = 1.0 -# <- @type -token[] purpose = ["default", "render"] -# <- @type - -rel material:binding:collection:Erasers = None -# <- @type -# ^ @module -# ^ @punctuation.delimiter -# ^ @module -# ^ @punctuation.delimiter -# ^ @module -# ^ @punctuation.delimiter -# ^ @variable -# ^ @constant.builtin diff --git a/tests/query/highlights/usd/subLayers.usda b/tests/query/highlights/usd/subLayers.usda deleted file mode 100644 index ddd1dd7af..000000000 --- a/tests/query/highlights/usd/subLayers.usda +++ /dev/null @@ -1,9 +0,0 @@ -#usda 1.0 -( - subLayers = [ - # <- @keyword - @./model_sub.usda@ (offset = 1) - # <- @string.special.url - # ^ @keyword - ] -) diff --git a/tests/query/highlights/wing/class.w b/tests/query/highlights/wing/class.w deleted file mode 100644 index 1507d7574..000000000 --- a/tests/query/highlights/wing/class.w +++ /dev/null @@ -1,21 +0,0 @@ -bring cloud; -// <- @keyword.import -// ^ @module - -class Foo { -// <- @keyword.type -// ^ @type -// ^ @punctuation.bracket - name: str; -//^ @property -// ^ @type.builtin -// ^ @punctuation.delimiter - new(name: str) { -//^ @keyword -// ^ @variable - this.name = name; -// ^ @punctuation.delimiter -// ^ @variable.member -// ^ @operator - } -} diff --git a/tests/query/highlights/wing/nested_method.w b/tests/query/highlights/wing/nested_method.w deleted file mode 100644 index 080d29793..000000000 --- a/tests/query/highlights/wing/nested_method.w +++ /dev/null @@ -1,4 +0,0 @@ -test1.test2.test3(); -// <- @variable -// ^ @variable.member -// ^ @function.method.call diff --git a/tests/query/highlights/xhp-intro.hack b/tests/query/highlights/xhp-intro.hack index 0f8cffe02..942d2ff00 100644 --- a/tests/query/highlights/xhp-intro.hack +++ b/tests/query/highlights/xhp-intro.hack @@ -5,23 +5,23 @@ use type Facebook\XHP\HTML\{XHPHTMLHelpers, a, form}; final xhp class a_post extends x\element { -// ^ @keyword.modifier -// ^ @keyword.modifier -// ^ @keyword +// ^ type.qualifier +// ^ type.qualifier +// ^ keyword use XHPHTMLHelpers; attribute string href @required; - // ^ @attribute + // ^ attribute attribute string target; - // ^ @keyword + // ^ keyword <<__Override>> protected async function renderAsync(): Awaitable { $id = $this->getID(); $anchor = {$this->getChildren()}; - // ^ @tag.delimiter - // ^ @tag + // ^ tag.delimiter + // ^ tag $form = (
setAttribute('href', '#'); - // ^ @function.method.call + // ^ method.call return $form; } diff --git a/tests/query/highlights/yaml/promql-on-prometheus-rules.yaml b/tests/query/highlights/yaml/promql-on-prometheus-rules.yaml deleted file mode 100644 index 910405418..000000000 --- a/tests/query/highlights/yaml/promql-on-prometheus-rules.yaml +++ /dev/null @@ -1,33 +0,0 @@ -groups: -- name: Hardware alerts - rules: - - alert: Node down - expr: up{job="node_exporter"} == 0 - # ^ @type - for: 3m - labels: - severity: warning - annotations: - title: Node {{ $labels.instance }} is down - description: Failed to scrape {{ $labels.job }} on {{ $labels.instance }} for more than 3 minutes. Node seems down. - - alert: Node down - expr: | - up{job="node_exporter"} == 0 - # ^ @type - for: 3m - labels: - severity: warning - - alert: Regex and String matching - expr: | - foo{path=~"^foo$"}[5m] or foo{path!~"[a-zA-Z0-9]{1,3}"}[5m] or foo{path="/api/users/{userId}"}[5m] or foo{path!="/api/users/{userId}"}[5m] - # ^ @type - # ^ @string.regexp - # ^ @string.regexp - # ^ @string - # ^ @string - for: 3m - labels: - severity: warning - annotations: - title: Foo - description: Bar diff --git a/tests/query/highlights/zsh/test.zsh b/tests/query/highlights/zsh/test.zsh deleted file mode 100644 index b1c4e398f..000000000 --- a/tests/query/highlights/zsh/test.zsh +++ /dev/null @@ -1,358 +0,0 @@ -#!/bin/zsh -# ^^^^^^^^ @comment @spell - -# Basic comment -# <- @comment @spell - -# Variables and assignments -name="value" -#^^^ @variable @constant -# ^ @operator -# ^^^^^^^ @string - -export PATH="/usr/bin:$PATH" -#^^^^^ @keyword.import -# ^^^^ @variable @constant @variable.builtin -# ^ @operator -# ^^^^^^^^^^^^^^^^ @string -# ^ @punctuation.special -# ^^^^ @variable.builtin - -# Function definition -function myfunction() { -#^^^^^^^ @keyword.function -# ^^^^^^^^^^ @function @number - echo "Hello World" - #^^^ @function.call @function.builtin @number - # ^^^^^^^^^^^^^ @string -} - -myfunction() { -#^^^^^^^^^ @function @number - local var="test" - #^^^^ @keyword - # ^^^ @variable @constant - # ^ @operator - # ^^^^^^ @string -} - -# Built-in commands -echo "Hello" -#^^^ @function.call @function.builtin @number -# ^^^^^^^ @string - -cd /home/user -#^ @function.call @function.builtin @number -# ^^^^^^^^^^ @variable.parameter @number - -ls -la -#^ @function.call @number -# ^^^ @variable.parameter @number - -# Control structures -if [[ -f "$file" ]]; then -#^ @keyword.conditional -# ^^ @punctuation.bracket -# ^^ @operator @operator -# ^^^^^^^ @string -# ^ @punctuation.special @none -# ^^ @punctuation.bracket -# ^ @punctuation.delimiter -# ^^^^ @keyword.conditional - echo "File exists" - #^^^ @function.call @function.builtin @number - # ^^^^^^^^^^^^^ @string -fi -#^ @keyword.conditional - -for i in {1..10}; do -#^^ @keyword.repeat -# ^^ @keyword.conditional -# ^ @punctuation.bracket -# ^ @number -# ^^ @operator -# ^^ @number -# ^ @punctuation.bracket -# ^ @punctuation.delimiter -# ^^ @keyword.repeat - echo $i - #^^^ @function.call @function.builtin @number - # ^ @punctuation.special -done -#^^^ @keyword.repeat - -while read line; do -#^^^^ @keyword.repeat -# ^^^^ @function.call @function.builtin @number -# ^^^^ @variable.parameter @number -# ^ @punctuation.delimiter -# ^^ @keyword.repeat - echo "$line" - #^^^ @function.call @function.builtin @number - # ^^^^^^^ @string - # ^ @punctuation.special @none -done -#^^^ @keyword.repeat - -case $input in -#^^^ @keyword.conditional -# ^ @punctuation.special @none -# ^^ @keyword.conditional - "yes"|"y") - #^^^^ @string @variable.parameter - # ^ @operator - # ^^^ @string @variable.parameter - # ^ @punctuation.bracket - echo "Yes" - #^^^ @function.call @function.builtin @number - # ^^^^^ @string - ;; - #^ @punctuation.delimiter - "no"|"n") - #^^^ @string @variable.parameter - # ^ @operator - # ^^^ @string @variable.parameter - # ^ @punctuation.bracket - echo "No" - #^^^ @function.call @function.builtin @number - # ^^^^ @string - ;; - #^ @punctuation.delimiter - *) - #^ @string.regexp - # ^ @punctuation.bracket - echo "Unknown" - #^^^ @function.call @function.builtin @number - # ^^^^^^^^^ @string - ;; - #^ @punctuation.delimiter -esac -#^^^ @keyword.conditional - -# Arrays -arr=(one two three) -#^^ @variable @constant -# ^ @operator -# ^ @punctuation.bracket -# ^ @punctuation.bracket - -echo ${arr[1]} -#^^^ @function.call @function.builtin @number -# ^ @punctuation.special -# ^ @punctuation.special -# ^ @punctuation.bracket -# ^ @number -# ^ @punctuation.bracket -# ^ @punctuation.special - -# Parameter expansion -echo ${name:-default} -#^^^ @function.call @function.builtin @number -# ^^ @punctuation.special -# ^ @punctuation.special - -echo ${#name} -#^^^ @function.call @function.builtin @number -# ^^ @punctuation.special -# ^ @punctuation.special - -# Command substitution -result=$(date) -#^^^^^ @variable @constant -# ^ @operator -# ^ @punctuation.special -# ^ @punctuation.special -# ^^^^ @function.call @number -# ^ @punctuation.special - -result=`date` -#^^^^^ @variable @constant -# ^ @operator -# ^^^^ @function.call @number - -# Pipes and redirection -ls | grep "test" > output.txt -#^ @function.call @number -# ^ @operator -# ^^^^ @function.call @number -# ^^^^^^ @string -# ^ @operator -# ^^^^^^^^^^ @string.special.path @number - -cat < input.txt >> output.txt -#^^ @function.call @number -# ^ @operator -# ^^^^^^^^^ @string.special.path @number -# ^^ @operator -# ^^^^^^^^^^ @string.special.path @number - -# Process substitution -diff <(ls dir1) <(ls dir2) -#^^^ @function.call @number -# ^ @punctuation.special -# ^ @punctuation.special -# ^^ @function.call @number -# ^^^^ @variable.parameter @number -# ^^ @punctuation.special -# ^^ @function.call @number -# ^^^^ @variable.parameter @number -# ^ @punctuation.special @punctuation.bracket - -# Test commands -[[ -f file.txt ]] -#^ @punctuation.bracket -# ^^ @operator @operator -# ^^ @punctuation.bracket - - [ -n "$var" ] -#^ @punctuation.bracket -# ^^ @operator @operator -# ^^^^^ @string -# ^ @punctuation.special -# ^ @punctuation.bracket - -# Arithmetic expansion -echo $((2 + 3)) -#^^^ @function.call @function.builtin @number -# ^ @punctuation.special -# ^^ @punctuation.special -# ^ @number -# ^ @operator -# ^ @number -# ^^ @punctuation.special @punctuation.bracket - -# Globbing patterns -ls *.txt -#^ @function.call @number - -# Brace expansion -echo {a,b,c} -#^^^ @function.call @function.builtin @number - -# Here documents -cat << EOF -#^^ @function.call @number -# ^^ @operator -# ^^^ @label -This is a heredoc -#^^^^^^^^^^^^^^^^^ @string -EOF -#^^ @label - -cat <<< "string" -#^^ @function.call @number -# ^^ @operator -# ^ @operator -# ^^^^^^^^ @string - -# Special variables -echo $0 $1 $@ $* $# $? -#^^^ @function.call @function.builtin @number -# ^^ @punctuation.special @none @variable.builtin -# ^ @variable.builtin -# ^^ @punctuation.special @none @variable.builtin -# ^ @variable.builtin -# ^^ @punctuation.special @none @variable.builtin -# ^ @variable.builtin -# ^^ @punctuation.special @none @variable.builtin -# ^ @variable.builtin -# ^^ @punctuation.special @none @variable.builtin -# ^ @variable.builtin -# ^^ @punctuation.special @none @variable.builtin -# ^ @variable.builtin -# NOTE: $$ is not captured by current query/grammar - -# Conditional operators -[[ $a == $b ]] && echo "equal" -#^ @punctuation.bracket -# ^ @punctuation.special @none -# ^^ @operator @operator -# ^ @punctuation.special @none -# ^^ @punctuation.bracket -# ^^ @operator -# ^^^^ @function.builtin @function.call @number -# ^^^^^^^ @string - -[[ $a != $b ]] || echo "not equal" -#^ @punctuation.bracket -# ^^ @punctuation.special @none -# ^^ @operator -# ^^ @punctuation.special @none -# ^^ @operator -# ^^^^ @function.call @function.builtin @number -# ^^^^^^^^^^^ @string - -# Background jobs -sleep 10 & -#^^^^ @function.call @number -# ^^ @number -# ^ @punctuation.delimiter - -# Negation - ! command -#^ @operator - #^^^^^^ @function.call @number - -# File descriptors -exec 3> file.txt -#^^^ @function.call @function.builtin @number -# ^ @operator -# ^ @operator -# ^^^^^^^^ @string.special.path @number - -# ZSH-specific features -setopt AUTO_CD -#^^^^^ @function.call @number -# ^^^^^^^ @variable.parameter @number - -autoload -U compinit -#^^^^^^^ @function.call @number -# ^^ @variable.parameter @number -# ^^^^^^^^ @variable.parameter @number - -# Associative arrays -typeset -A hash -#^^^^^^ @keyword -# ^^ @variable.parameter @number -# ^^^^ @variable.parameter @constant - -hash[key]="value" -#^^^ @variable @constant -# ^ punctuation.bracket -# ^ punctuation.bracket -# ^ @operator -# ^^^^^^^ @string - -# Regular expressions -[[ "text" =~ ^[a-z]+$ ]] -#^ @punctuation.bracket -# ^^^^^^ @string -# ^^ @operator -# ^^^^^^^^^ @string.regexp -# ^^ @punctuation.bracket - -# Quotes and escaping -echo "double quotes with $var" -#^^^ @function.call @function.builtin @number -# ^^^^^^^^^^^^^^^^^^^^^^^^^ @string -# ^ @punctuation.special @none - -echo 'single quotes $var' -#^^^ @function.call @function.builtin @number -# ^^^^^^^^^^^^^^^^^^^^ @string - -echo $'ansi-c quotes\n' -#^^^ @function.call @function.builtin @number -# ^^^^^^^^^^^^^^^^^ @string - -echo "escaped \" quote" -#^^^ @function.call @function.builtin @number -# ^^^^^^^^^^^^^^^^^^ @string - -# Command chaining -cmd1 && cmd2 || cmd3 -#^^^ @function.call @number -# ^^ @operator -# ^^^^ @function.call @number -# ^^ @operator -# ^^^^ @function.call @number diff --git a/tests/query/highlights_spec.lua b/tests/query/highlights_spec.lua index e59feb9f4..ff022ba21 100644 --- a/tests/query/highlights_spec.lua +++ b/tests/query/highlights_spec.lua @@ -1,40 +1,44 @@ -local config = require('nvim-treesitter.config') -local ts = vim.treesitter +local highlighter = require "vim.treesitter.highlighter" +local ts_utils = require "nvim-treesitter.ts_utils" +local parsers = require "nvim-treesitter.parsers" local COMMENT_NODES = { - markdown = 'html_block', - haskell = 'haddock', + markdown = "html_block", } local function check_assertions(file) local buf = vim.fn.bufadd(file) vim.fn.bufload(file) - local ft = vim.bo[buf].filetype - local lang = vim.treesitter.language.get_lang(ft) or ft - local comment_node = COMMENT_NODES[lang] or 'comment' - local assertions = vim.fn.json_decode(vim.fn.system({ - os.getenv('HLASSERT'), - '-p', - config.get_install_dir('parser') .. '/' .. lang .. '.so', - '-s', - file, - '-c', - comment_node, - })) - assert.True(#assertions > 0, 'No assertions detected!') + local lang = parsers.get_buf_lang(buf) + assert.same( + 1, + vim.fn.executable "highlight-assertions", + '"highlight-assertions" not executable!' + .. ' Get it via "cargo install --git https://github.com/theHamsta/highlight-assertions"' + ) + local comment_node = COMMENT_NODES[lang] or "comment" + local assertions = vim.fn.json_decode( + vim.fn.system( + "highlight-assertions -p '" + .. vim.api.nvim_get_runtime_file("parser/" .. lang .. ".so", false)[1] + .. "' -s '" + .. file + .. "' -c " + .. comment_node + ) + ) + local parser = parsers.get_parser(buf, lang) - local parser = ts.get_parser(buf) - - parser:parse(true) + local self = highlighter.new(parser, {}) + assert.True(#assertions > 0, "No assertions detected!") for _, assertion in ipairs(assertions) do local row = assertion.position.row local col = assertion.position.column - assert.is.number(row) - assert.is.number(col) local captures = {} - parser:for_each_tree(function(tstree, tree) + local highlights = {} + self.tree:for_each_tree(function(tstree, tree) if not tstree then return end @@ -47,54 +51,51 @@ local function check_assertions(file) return end - local query = ts.query.get(tree:lang(), 'highlights') - if not query then + local query = self:get_query(tree:lang()) + + -- Some injected languages may not have highlight queries. + if not query:query() then return end - for id, node, _ in query:iter_captures(root, buf, row, row + 1) do - if ts.is_in_node_range(node, row, col) then - local capture = query.captures[id] - if capture ~= nil and capture ~= 'conceal' and capture ~= 'spell' then - captures[capture] = true + local iter = query:query():iter_captures(root, self.bufnr, row, row + 1) + + for capture, node, _ in iter do + local hl = query.hl_cache[capture] + assert.is.truthy(hl) + + assert.Truthy(node) + assert.is.number(row) + assert.is.number(col) + if hl and ts_utils.is_in_node_range(node, row, col) then + local c = query._query.captures[capture] -- name of the capture in the query + if c ~= nil and c ~= "spell" and c ~= "conceal" then + captures[c] = true + highlights[c] = true end end end - end) - if assertion.expected_capture_name:match('^!') then - assert.Falsy( - captures[assertion.expected_capture_name:sub(2)], - 'Error in ' - .. file - .. ':' - .. (row + 1) - .. ':' - .. (col + 1) - .. ': expected "' - .. assertion.expected_capture_name - .. '", captures: ' - .. vim.inspect(vim.tbl_keys(captures)) - ) - else - assert.True( - captures[assertion.expected_capture_name], - 'Error in ' - .. file - .. ':' - .. (row + 1) - .. ':' - .. (col + 1) - .. ': expected "' - .. assertion.expected_capture_name - .. '", captures: ' - .. vim.inspect(vim.tbl_keys(captures)) - ) - end + end, true) + assert.True( + captures[assertion.expected_capture_name] or highlights[assertion.expected_capture_name], + "Error in at " + .. file + .. ":" + .. (row + 1) + .. ":" + .. (col + 1) + .. ': expected "' + .. assertion.expected_capture_name + .. '", captures: ' + .. vim.inspect(vim.tbl_keys(captures)) + .. '", highlights: ' + .. vim.inspect(vim.tbl_keys(highlights)) + ) end end -describe('highlight queries', function() - local files = vim.fn.split(vim.fn.glob('tests/query/highlights/**/*.*')) +describe("highlight queries", function() + local files = vim.fn.split(vim.fn.glob "tests/query/highlights/**/*.*") for _, file in ipairs(files) do it(file, function() check_assertions(file) diff --git a/tests/query/injection_spec.lua b/tests/query/injection_spec.lua index 63734dd5b..b10b7450f 100644 --- a/tests/query/injection_spec.lua +++ b/tests/query/injection_spec.lua @@ -1,76 +1,65 @@ -local config = require('nvim-treesitter.config') -local ts = vim.treesitter +require "nvim-treesitter.highlight" -- yes, this is necessary to set the hlmap +local highlighter = require "vim.treesitter.highlighter" +local configs = require "nvim-treesitter.configs" +local ts_utils = require "nvim-treesitter.ts_utils" +local parsers = require "nvim-treesitter.parsers" local function check_assertions(file) local buf = vim.fn.bufadd(file) vim.fn.bufload(file) - local ft = vim.bo[buf].filetype - local lang = vim.treesitter.language.get_lang(ft) or ft - local assertions = vim.fn.json_decode(vim.fn.system({ - os.getenv('HLASSERT'), - '-p', - config.get_install_dir('parser') .. '/' .. lang .. '.so', - '-s', - file, - })) - local parser = ts.get_parser(buf, lang) + local lang = parsers.get_buf_lang(buf) + assert.same( + 1, + vim.fn.executable "highlight-assertions", + '"highlight-assertions" not executable!' + .. ' Get it via "cargo install --git https://github.com/theHamsta/highlight-assertions"' + ) + local assertions = vim.fn.json_decode( + vim.fn.system( + "highlight-assertions -p '" .. configs.get_parser_install_dir() .. "/" .. lang .. ".so'" .. " -s '" .. file .. "'" + ) + ) + local parser = parsers.get_parser(buf, lang) - local top_level_root = parser:parse(true)[1]:root() + local self = highlighter.new(parser, {}) + local top_level_root = parser:parse()[1]:root() for _, assertion in ipairs(assertions) do local row = assertion.position.row local col = assertion.position.column - local neg_assert = assertion.expected_capture_name:match('^!') - assertion.expected_capture_name = neg_assert and assertion.expected_capture_name:sub(2) - or assertion.expected_capture_name local found = false - parser:for_each_tree(function(tstree, tree) + self.tree:for_each_tree(function(tstree, tree) if not tstree then return end + local root = tstree:root() - --- If there are multiple tree with the smallest range possible - --- Check all of them to see if they fit or not - if not ts.is_in_node_range(root, row, col) or root == top_level_root then - return - end - if assertion.expected_capture_name == tree:lang() then + if + ts_utils.is_in_node_range(root, row, col) + and assertion.expected_capture_name == tree:lang() + and root ~= top_level_root + then found = true end - end) - if neg_assert then - assert.False( - found, - 'Error in ' - .. file - .. ':' - .. (row + 1) - .. ':' - .. (col + 1) - .. ': expected "' - .. assertion.expected_capture_name - .. '" not to be injected here!' - ) - else - assert.True( - found, - 'Error in ' - .. file - .. ':' - .. (row + 1) - .. ':' - .. (col + 1) - .. ': expected "' - .. assertion.expected_capture_name - .. '" to be injected here!' - ) - end + end, true) + assert.True( + found, + "Error in at " + .. file + .. ":" + .. (row + 1) + .. ":" + .. (col + 1) + .. ': expected "' + .. assertion.expected_capture_name + .. '" to be injected here!' + ) end end -describe('injections', function() - local files = vim.fn.split(vim.fn.glob('tests/query/injections/**/*.*')) +describe("injections", function() + local files = vim.fn.split(vim.fn.glob "tests/query/injections/**/*.*") for _, file in ipairs(files) do it(file, function() check_assertions(file) diff --git a/tests/query/injections/cuda/macro-self-injection.cu b/tests/query/injections/cuda/macro-self-injection.cu index a91184287..1acef197b 100644 --- a/tests/query/injections/cuda/macro-self-injection.cu +++ b/tests/query/injections/cuda/macro-self-injection.cu @@ -1,2 +1,2 @@ #define FOO(X,Y) X + Y -// ^ @cuda +// ^ cuda diff --git a/tests/query/injections/dockerfile/bash-on-run-instructions.dockerfile b/tests/query/injections/dockerfile/bash-on-run-instructions.dockerfile deleted file mode 100644 index 00621f1a3..000000000 --- a/tests/query/injections/dockerfile/bash-on-run-instructions.dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM foo -RUN bar -# ^ @bash -RUN \ - baz -# ^ @bash diff --git a/tests/query/injections/ecma/ecma-test-injections.js b/tests/query/injections/ecma/ecma-test-injections.js deleted file mode 100644 index 16ddd3c6b..000000000 --- a/tests/query/injections/ecma/ecma-test-injections.js +++ /dev/null @@ -1,9 +0,0 @@ -html`

`; - // ^ @html -html(`

`); - // ^ @html -svg`

`; - // ^ @html -svg(`

`); - // ^ @html - diff --git a/tests/query/injections/html/test-html-injections.html b/tests/query/injections/html/test-html-injections.html deleted file mode 100644 index 8b08b3f38..000000000 --- a/tests/query/injections/html/test-html-injections.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - Test div to test css injections for style attributes -
- - - - - - - - diff --git a/tests/query/injections/http/injections.http b/tests/query/injections/http/injections.http deleted file mode 100644 index 0f339cb6f..000000000 --- a/tests/query/injections/http/injections.http +++ /dev/null @@ -1,21 +0,0 @@ -### post-request script -GET https://jsonplaceholder.typicode.com/posts/3 - -# @lang=lua -> {% -local body = vim.json.decode(response.body) -client.global.set("postId", body.id) --- ^ @lua -%} - - -### run request with variable - -GET https://jsonplaceholder.typicode.com/posts/{{postId}} - -> {% - client.global.set("auth_token", response.body.jwt); - // ^ @javascript -%} - -### vim: ft=http diff --git a/tests/query/injections/nix/test-nix-injections.nix b/tests/query/injections/nix/test-nix-injections.nix deleted file mode 100644 index f0907a901..000000000 --- a/tests/query/injections/nix/test-nix-injections.nix +++ /dev/null @@ -1,79 +0,0 @@ -# NOTE: This file is for testing queries. If evaluated with nix, this will probably error. -{ pkgs, stdenv, lib }: let - match = builtins.match; -in { - regex = builtins.match "^.*[{](.+)[}].*$" "blahblah {something} blahblah" [ "something" ]; - - regex2 = match "^.*[{](.+)[}].*$" "blahblah {something} blahblah" [ "something" ]; - - drv1 = stdenv.mkDerivation { - buildPhase = "mkdir $out"; - installPhase = '' - echo "${bar}" > $out/foo.txt - echo "baz"" >> $out/foo.txt - ''; - }; - - drv2 = pkgs.writeShellApplication { - name = "shellApp"; - buildInputs = []; - text = '' - echo "Hello world!" - ''; - }; - - drv3 = pkgs.runCommand "foo-bar" {} '' - mkir $out - echo "bar" > $out/foo.txt - ''; - - drv4 = pkgs.runCommandNoCC "foo-bar" {} '' - mkir $out - echo "bar" > $out/foo.txt - ''; - - drv5 = pkgs.writeShellScriptBin "hello" '' - echo "Hello world!" - ''; - - drv6 = pkgs.writeFishBin "hello" '' - echo "Hello world!" - ''; - - drv7 = pkgs.writeHaskellBin "hello" '' - main :: IO () - main = putStrLn "Hello world!" - ''; - - drv8 = pkgs.writeJSBin "hello" '' - console.log('Hello world!'); - ''; - - drv9 = pkgs.writePerlBin "hello" '' - print("Hello world!\n"); - ''; - - drv10 = pkgs.writePythonBin "hello" '' - print("Hello world!"); - ''; - - drv11 = pkgs.writeRustBin "hello" '' - fn main() { - println!("Hello world!"); - } - ''; - - drv12 = lib.nixos.runTest { - nodes = null; - testScript = '' - print("Hello world!"); - ''; - }; - - mod1 = { - type = "lua"; - config = '' - require('nvim-treesitter.config').setup() - ''; - }; -} diff --git a/tests/query/injections/promql/regex.promql b/tests/query/injections/promql/regex.promql deleted file mode 100644 index 08ed74640..000000000 --- a/tests/query/injections/promql/regex.promql +++ /dev/null @@ -1,10 +0,0 @@ -foo{path=~"^foo$"}[5m] or -# ^ @regex -foo{path!~"[a-zA-Z0-9]{1,3}"}[5m] or -# ^ @regex -foo{path="/api/users/{userId}"}[5m] or -# ^ @!regex -foo{path!="/api/users/{userId}"}[5m] -# ^ @!regex - -# vim: ft=promql diff --git a/tests/query/injections/python/test.py b/tests/query/injections/python/test.py deleted file mode 100644 index 1d6a0a465..000000000 --- a/tests/query/injections/python/test.py +++ /dev/null @@ -1,18 +0,0 @@ -import re - -re_test = re.compile(r"^(?P\d{4}) (?P\d) \w\s{,3}$") -# ^ @regex -re_test = re.compile( - # comment - # ^ @comment - r"^(?P\d{4}) " - # comment - # ^ @comment - r"(?P\d) \w\s{,3}$" - # ^ @regex - # comment - # comment - # ^ @comment -) -print("foo %s bar %d" % ("arg1", 2)) -# ^ @printf diff --git a/tests/query/injections/query/test-query-injections.scm b/tests/query/injections/query/test-query-injections.scm deleted file mode 100644 index f382eddd9..000000000 --- a/tests/query/injections/query/test-query-injections.scm +++ /dev/null @@ -1,27 +0,0 @@ -; vim: ft=query -; format-ignore -(((symbol) @constant - (#not-lua-match? @constant "^_*[A-Z][A-Z0-9_]*$")) -; ^ @luap -) - -; format-ignore -(((tag - (attributes - (attribute - (attribute_name) @keyword))) - (#match? @keyword "^(:|v-bind|v-|\\@)")) -; ^ @regex -) - -((comment) @injection.language - . - [ - (string_expression - (string_fragment) @injection.content) - (indented_string_expression - (string_fragment) @injection.content) - ] - (#gsub! @injection.language "#%s*([%w%p]+)%s*" "%1") - ; ^ @luap - (#set! injection.combined)) diff --git a/tests/query/injections/ruby/test-ruby-debugger.rb b/tests/query/injections/ruby/test-ruby-debugger.rb deleted file mode 100644 index 1dd8632c3..000000000 --- a/tests/query/injections/ruby/test-ruby-debugger.rb +++ /dev/null @@ -1,11 +0,0 @@ -binding.b(do: "puts 'Hello, world!'") -# ^ @ruby - -binding.b(pre: "pp [1, 2, 3]") -# ^ @ruby - -binding.break(do: "puts 'Hello, world!'") -# ^ @ruby - -binding.break(pre: "pp [1, 2, 3]") -# ^ @ruby diff --git a/tests/query/injections/starlark/test.bzl b/tests/query/injections/starlark/test.bzl deleted file mode 100644 index 4a8af5172..000000000 --- a/tests/query/injections/starlark/test.bzl +++ /dev/null @@ -1,5 +0,0 @@ -# split -# ^ @comment -assert_eq('foo bar'.split(' '), ['foo', 'bar']) -assert_eq("foo %s bar %d" % ("arg1", 2), "foo arg1 bar 2") -# ^ @printf diff --git a/tests/query/injections/svelte/test-svelte-injections.svelte b/tests/query/injections/svelte/test-svelte-injections.svelte deleted file mode 100644 index ea88aa6a9..000000000 --- a/tests/query/injections/svelte/test-svelte-injections.svelte +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - -
-

Test file

- {#each someItems as someItem} - -
{someItem}
- - {/each} - -
diff --git a/tests/query/injections/vue/negative-assertions.vue b/tests/query/injections/vue/negative-assertions.vue deleted file mode 100644 index 000702a17..000000000 --- a/tests/query/injections/vue/negative-assertions.vue +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/tests/query/injections/vue/test-vue-injections.vue b/tests/query/injections/vue/test-vue-injections.vue deleted file mode 100644 index 4966e6ac0..000000000 --- a/tests/query/injections/vue/test-vue-injections.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // const file = files[0]; diff --git a/tests/query/injections/yaml/bash-on-github-actions.yml b/tests/query/injections/yaml/bash-on-github-actions.yml index 5c732b09b..ba56de193 100644 --- a/tests/query/injections/yaml/bash-on-github-actions.yml +++ b/tests/query/injections/yaml/bash-on-github-actions.yml @@ -14,10 +14,10 @@ jobs: node-version: '16' - name: Install dependencies run: npm ci - # ^ @bash + # ^ bash - name: Run tests run: npm test - # ^ @bash + # ^ bash - name: Parse Petalisp run: | git submodule init @@ -27,6 +27,6 @@ jobs: else echo "Successfully parsed Petalisp" fi - # ^ @bash + # ^ bash - name: Run tests run: npm test diff --git a/tests/query/injections/yaml/bash-on-taskfiles.yml b/tests/query/injections/yaml/bash-on-taskfiles.yml deleted file mode 100644 index c99dc4667..000000000 --- a/tests/query/injections/yaml/bash-on-taskfiles.yml +++ /dev/null @@ -1,24 +0,0 @@ -# https://taskfile.dev - -version: '3' - -vars: - GREETING: - sh: echo "Hello, World!" - # ^ @bash - -tasks: - default: - cmds: - - echo "{{.GREETING}}" - # ^ @bash - silent: true - cmd: - cmd: echo "{{.GREETING}}" - # ^ @bash - silent: true - cmd-block: - cmd: | - echo "{{.GREETING}}" - # ^ @bash - silent: true diff --git a/tests/query/injections/yaml/promql-on-prometheus-rules.yaml b/tests/query/injections/yaml/promql-on-prometheus-rules.yaml deleted file mode 100644 index 942fb1369..000000000 --- a/tests/query/injections/yaml/promql-on-prometheus-rules.yaml +++ /dev/null @@ -1,33 +0,0 @@ -groups: -- name: Hardware alerts - rules: - - alert: Node down - expr: up{job="node_exporter"} == 0 - # ^ @promql - for: 3m - labels: - severity: warning - annotations: - title: Node {{ $labels.instance }} is down - description: Failed to scrape {{ $labels.job }} on {{ $labels.instance }} for more than 3 minutes. Node seems down. - - alert: Node down - expr: | - up{job="node_exporter"} == 0 - # ^ @promql - for: 3m - labels: - severity: warning - - alert: Regex and String matching - expr: | - foo{path=~"^foo$"}[5m] or foo{path!~"[a-zA-Z0-9]{1,3}"}[5m] or foo{path="/api/users/{userId}"}[5m] or foo{path!="/api/users/{userId}"}[5m] - # ^ @promql - # ^ @regex - # ^ @regex - # ^ @!regex - # ^ @!regex - for: 3m - labels: - severity: warning - annotations: - title: Foo - description: Bar diff --git a/tests/unit/ts_utils_spec.lua b/tests/unit/ts_utils_spec.lua new file mode 100644 index 000000000..a3b334413 --- /dev/null +++ b/tests/unit/ts_utils_spec.lua @@ -0,0 +1,108 @@ +local tsutils = require "nvim-treesitter.ts_utils" + +describe("is_in_node_range", function() + local function test_is_in_node_range(line, col) + local node = { + range = function() + return unpack { 0, 3, 2, 5 } + end, + } + return tsutils.is_in_node_range(node, line, col) + end + + it("returns false before node start", function() + assert.is_false(test_is_in_node_range(0, 0)) + assert.is_false(test_is_in_node_range(0, 1)) + assert.is_false(test_is_in_node_range(0, 2)) + end) + + it("returns true at node start", function() + assert.is_true(test_is_in_node_range(0, 3)) + end) + + it("returns true on first line of the node", function() + assert.is_true(test_is_in_node_range(0, 4)) + end) + + it("returns true between node lines", function() + assert.is_true(test_is_in_node_range(1, 2)) + assert.is_true(test_is_in_node_range(1, 20)) + end) + + it("returns false on node end", function() + -- Ranges are end-exclusive + assert.is_false(test_is_in_node_range(2, 5)) + end) + + it("returns false after node end", function() + assert.is_false(test_is_in_node_range(2, 6)) + assert.is_false(test_is_in_node_range(3, 0)) + end) +end) + +describe("update_selection", function() + local function get_updated_selection(case) + vim.api.nvim_buf_set_lines(0, 0, -1, false, case.lines) + tsutils.update_selection(0, case.node, case.selection_mode) + vim.cmd "normal! y" + return vim.fn.getreg '"' + end + + it("charwise1", function() + assert.equal( + get_updated_selection { + lines = { "foo", "", "bar" }, + node = { 0, 0, 2, 1 }, + selection_mode = "v", + }, + "foo\n\nb" + ) + it("charwise2", function() end) + assert.equal( + get_updated_selection { + lines = { "foo", "", "bar" }, + node = { 0, 1, 2, 1 }, + selection_mode = "v", + }, + "oo\n\nb" + ) + it("charwise3", function() end) + assert.equal( + get_updated_selection { + lines = { "foo", "", "bar" }, + node = { 0, 2, 2, 1 }, + selection_mode = "v", + }, + "o\n\nb" + ) + it("charwise4", function() end) + assert.equal( + get_updated_selection { + lines = { "foo", "", "bar" }, + node = { 0, 3, 2, 1 }, + selection_mode = "v", + }, + "\n\nb" + ) + end) + it("linewise", function() + assert.equal( + get_updated_selection { + lines = { "foo", "", "bar" }, + node = { 0, 3, 2, 1 }, + selection_mode = "V", + }, + "foo\n\nbar\n" + ) + end) + it("blockwise", function() + assert.equal( + get_updated_selection { + lines = { "foo", "", "bar" }, + node = { 0, 3, 2, 1 }, + selection_mode = "", + }, + "foo\n\nbar" + ) + end) +end)