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/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..f68dd2486 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..d883b8f2d 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,7 +2,7 @@ name: Feature request about: Suggest an idea for this project title: "" -type: enhancement +labels: enhancement assignees: "" --- diff --git a/.github/ISSUE_TEMPLATE/highlighting_issue.yml b/.github/ISSUE_TEMPLATE/highlighting_issue.yml index 4b9b0a4a7..a429b5eb8 100644 --- a/.github/ISSUE_TEMPLATE/highlighting_issue.yml +++ b/.github/ISSUE_TEMPLATE/highlighting_issue.yml @@ -1,6 +1,5 @@ name: Highlighting issue description: Missing or incorrect highlights or you want to change the way something is highlighted -type: 'bug' labels: [highlights] body: 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/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..cd0e51982 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,50 +1,51 @@ -name: Lint +name: Linting and style checking on: - push: - branches: - - "main" pull_request: branches: - - "main" - workflow_dispatch: + - "master" 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@v4 - - 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: Run Luacheck + run: luacheck . + + stylua: + name: StyLua + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Lint with stylua + uses: JohnnyMorganz/stylua-action@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + version: latest + args: --check . + + format-queries: + name: Lint queries + runs-on: ubuntu-latest + env: + NVIM_TAG: stable + steps: + - uses: actions/checkout@v4 + - name: Prepare + run: | + bash ./scripts/ci-install.sh - name: Lint - run: make checklua - - queries: - name: Lint query files - runs-on: ubuntu-slim - 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 + nvim --headless -c "TSInstallSync query" -c "q" + nvim -l scripts/format-queries.lua git diff --exit-code diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..11f3ffc14 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,24 @@ +name: "release" +on: + push: + tags: # Will upload to luarocks.org + - "*" + pull_request: # Will test a local install without uploading to luarocks.org + paths: + - 'contrib/*.rockspec' + - .github/workflows/release.yml + +jobs: + luarocks-upload: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: nvim-neorocks/luarocks-tag-release@v5 + env: + LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }} + with: + name: nvim-treesitter + detailed_description: | + The goal of nvim-treesitter is both to provide a simple and easy way to use the interface for tree-sitter in Neovim + and to provide some basic functionality such as highlighting based on it. + template: contrib/nvim-treesitter-luarocks.template 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..bc4a18d52 100644 --- a/.github/workflows/test-queries.yml +++ b/.github/workflows/test-queries.yml @@ -1,21 +1,88 @@ -name: Tests +name: Test queries on: push: branches: - - "main" + - "master" pull_request: 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-latest, macos-14] + cc: [gcc, clang] + nvim_tag: [stable] + exclude: + - os: ubuntu-latest + cc: clang + nvim_tag: stable + + - os: macos-14 + cc: gcc + nvim_tag: stable + + - os: windows-latest + cc: clang + nvim_tag: stable + + include: + - os: windows-latest + cc: cl + nvim_tag: nightly + + - os: ubuntu-latest + cc: gcc + nvim_tag: nightly + + name: Parser compilation + runs-on: ${{ matrix.os }} + env: + CC: ${{ matrix.cc }} + NVIM: ${{ matrix.os == 'windows-latest' && 'nvim-win64\\bin\\nvim.exe' || 'nvim' }} + ALLOWED_INSTALLATION_FAILURES: ${{ matrix.os == 'windows-latest' && 'rnoweb' }} + steps: + - uses: actions/checkout@v4 + - uses: tree-sitter/setup-action/cli@v1 + - uses: ilammy/msvc-dev-cmd@v1 + + - name: Install and prepare Neovim + env: + NVIM_TAG: ${{ matrix.nvim_tag }} + run: | + bash ./scripts/ci-install.sh + + - name: Setup Parsers Cache + id: parsers-cache + uses: actions/cache@v4 + with: + path: | + ./parser/ + ~/AppData/Local/nvim/pack/nvim-treesitter/start/nvim-treesitter/parser/ + key: parsers-${{ join(matrix.*, '-') }}-${{ hashFiles( + './lockfile.json', + './lua/nvim-treesitter/install.lua', + './lua/nvim-treesitter/parsers.lua', + './lua/nvim-treesitter/shell_command_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: runner.os == 'Windows' + run: cp -r ~/AppData/Local/nvim/pack/nvim-treesitter/start/nvim-treesitter/parser/* parser + + - name: Check query files + run: $NVIM -l scripts/check-queries.lua diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..5c775eda4 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,64 @@ +name: Tests + +on: + push: + branches: + - "master" + pull_request: + 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@v4 + - uses: tree-sitter/setup-action/cli@v1 + + - 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.6/highlight-assertions_v0.1.6_x86_64-unknown-linux-gnu.tar.gz | tar -xz + cp highlight-assertions /usr/local/bin + + - name: Install and prepare Neovim + env: + NVIM_TAG: stable + run: | + bash ./scripts/ci-install.sh + + - name: Setup Parsers Cache + id: parsers-cache + uses: actions/cache@v4 + with: + path: | + ./parser/ + ~/AppData/Local/nvim/pack/nvim-treesitter/start/nvim-treesitter/parser/ + key: parsers-${{ join(matrix.*, '-') }}-${{ hashFiles( + './lockfile.json', + './lua/nvim-treesitter/install.lua', + './lua/nvim-treesitter/parsers.lua', + './lua/nvim-treesitter/shell_selectors.lua') }} + + - name: Compile parsers Unix like + 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..70d628742 --- /dev/null +++ b/.github/workflows/update-lockfile.yml @@ -0,0 +1,58 @@ +name: Update lockfile + +on: + schedule: + - cron: "30 6 * * *" + workflow_dispatch: + +jobs: + update-lockfile: + name: Update lockfile + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: master + + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ vars.TOKEN_ID }} + private-key: ${{ secrets.TOKEN_PRIVATE_KEY }} + + - name: Prepare + env: + NVIM_TAG: stable + run: | + wget https://github.com/josephburnett/jd/releases/download/v1.7.1/jd-amd64-linux + mv jd-amd64-linux /tmp/jd + chmod +x /tmp/jd + bash scripts/ci-install.sh + + - name: Update parsers + env: + SKIP_LOCKFILE_UPDATE_FOR_LANGS: "djot" + run: | + cp lockfile.json /tmp/old_lockfile.json + nvim -l scripts/write-lockfile.lua + # Pretty print + cp lockfile.json /tmp/lockfile.json + cat /tmp/lockfile.json | jq --sort-keys > lockfile.json + UPDATED_PARSERS=$(/tmp/jd -f merge /tmp/old_lockfile.json lockfile.json | jq -r 'keys | join(", ")') + echo "UPDATED_PARSERS=$UPDATED_PARSERS" >> $GITHUB_ENV + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ steps.app-token.outputs.token }} + sign-commits: true + commit-message: "bot(lockfile): update ${{ env.UPDATED_PARSERS }}" + title: "Update lockfile.json: ${{ env.UPDATED_PARSERS }}" + body: "[beep boop](https://github.com/peter-evans/create-pull-request)" + branch: update-lockfile-pr + base: ${{ github.head_ref }} + + - name: Enable Pull Request Automerge + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: gh pr merge --rebase --auto update-lockfile-pr 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..a3fa018e5 --- /dev/null +++ b/.github/workflows/update-readme.yml @@ -0,0 +1,46 @@ +name: Update README + +on: + push: + branches: + - master + workflow_dispatch: + +jobs: + update-readme: + name: Update README + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ vars.TOKEN_ID }} + private-key: ${{ secrets.TOKEN_PRIVATE_KEY }} + + - name: Prepare + env: + NVIM_TAG: stable + run: | + bash ./scripts/ci-install.sh + + - name: Check README + run: | + nvim -l scripts/update-readme.lua || echo 'Needs update' + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ steps.app-token.outputs.token }} + sign-commits: true + commit-message: "bot(readme): update" + title: Update README + body: "[beep boop](https://github.com/peter-evans/create-pull-request)" + branch: update-readme-pr + base: ${{ github.head_ref }} + + - name: Enable Pull Request Automerge + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: gh pr merge --rebase --auto update-readme-pr diff --git a/.gitignore b/.gitignore index ca538329d..0ac164cd9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ -.test-deps doc/tags .luacheckcache /tags nvim.appimage -nvim-linux-x86_64* +nvim-linux64* 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 index 3917da0e2..8dc060501 100644 --- a/.luarc.json +++ b/.luarc.json @@ -1,18 +1,15 @@ { "$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json", "runtime": { - "version": "LuaJIT" + "version": "LuaJIT" }, "workspace": { "library": [ + "lua", "$VIMRUNTIME", - "${3rd}/busted/library" + "${3rd}/luv/library" ], - "ignoreDir": [ - ".test-deps", - "tests" - ], - "checkThirdParty": "Disable" + "checkThirdParty": false }, "diagnostics": { "groupFileStatus": { 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..23321f0f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,103 +1,79 @@ # 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 +[Matrix channel], so we can help you with any question you might have! -## 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 +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. +- 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://github.com/nvim-treesitter/nvim-treesitter#supported-languages), + 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. #### Inheriting languages 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) @@ -108,7 +84,7 @@ 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`. +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 the provided formatter `./scripts/format-queries.lua` on a single file (ending in `.scm`) or directory to format. Should you need to preserve a specific format for a node, you can exempt it (and all contained nodes) by placing before it ```query @@ -117,10 +93,7 @@ Should you need to preserve a specific format for a node, you can exempt it (and ### 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. - -The valid captures are listed below. +As languages differ quite a lot, here is a set of captures available to you when building a `highlights.scm` query. Note that your color scheme needs to define (or link) these captures as highlight groups. #### Identifiers @@ -279,202 +252,45 @@ Mainly for markup languages. #### Non-highlighting captures ```query +@none ; completely disable the highlight @conceal ; captures that are only meant to be concealed ``` ->[!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 @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). +The main types of nodes which are 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). +Captures can be restricted according to node contents using [predicates](https://neovim.io/doc/user/treesitter.html#treesitter-predicates). For performance reasons, prefer earlier predicates in this list: ->[!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) +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 +#### Conceal +Captures can be concealed by setting the [`conceal` metadata](https://neovim.io/doc/user/treesitter.html#treesitter-highlight-conceal), e.g.., ```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 + (fenced_code_block_delimiter @markup.raw.block (#set! conceal "")) ``` +The capture should be meaningful to allow proper highlighting when `set conceallevel=0`. If the unconcealed capture should not be highlighted (e.g., because an earlier pattern handles this), you can use `@conceal`. -#### Directives - -Nodes contain metadata that can be modified via [directives](https://neovim.io/doc/user/treesitter.html#treesitter-directives). +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). #### 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`. +`#set! priority ` directive (see `:h treesitter-highlight-priority`). +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). ### Locals @@ -482,8 +298,7 @@ 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. +**does not use locals for highlighting**. ```query @local.definition ; various definitions @@ -504,7 +319,7 @@ are only provided for limited backwards compatibility. @local.reference ; identifier reference ``` -#### Definition scope +#### Definition Scope You can set the scope of a definition by setting the `scope` property on the definition. @@ -530,7 +345,57 @@ 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 : + +```query +@fold ; fold this node +``` + +If the `folds.scm` query is not present, this will fall back to the `@local.scope` captures in the `locals` +query. + +### Injections + +Some captures are related to language injection (like markdown code blocks). They are used in `injections.scm`. + +If you want to dynamically detect the language (e.g. for Markdown blocks) use the `@injection.language` to capture +the node describing the language and `@injection.content` to describe the injection region. + +```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 +``` + +For example, to inject javascript into HTML's ` +``` + +```query +(script_element + (raw_text) @injection.content + (#set! injection.language "javascript")) ; set the parser language for @injection.content region to javascript +``` + +For regions that don't have a corresponding `@injection.language`, you need to manually set the language +through `(#set injection.language "lang_name")` + +To combine all matches of a pattern as one single block of content, add `(#set! injection.combined)` to such pattern + +### Indents + +```query +@indent.begin ; indent children when matching this node +@indent.end ; marks the end of indented block +@indent.align ; behaves like python aligned/hanging indent +@indent.dedent ; dedent children when matching this node +@indent.branch ; dedent itself when matching this node +@indent.ignore ; do not indent in this node +@indent.auto ; behaves like 'autoindent' buffer option +@indent.zero ; sets this node at position 0 (no indent) +``` + +[Matrix channel]: https://matrix.to/#/#nvim-treesitter:matrix.org diff --git a/Makefile b/Makefile index e22e2e6ab..338c75463 100644 --- a/Makefile +++ b/Makefile @@ -1,139 +1,7 @@ -NVIM_VERSION ?= nightly +# https://github.com/luarocks/luarocks/wiki/Creating-a-Makefile-that-plays-nice-with-LuaRocks +build: + echo "Do nothing" -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) +install: + mkdir -p $(INST_LUADIR) + cp -r lua/* $(INST_LUADIR) diff --git a/README.md b/README.md index 235df2dc3..1205209cd 100644 --- a/README.md +++ b/README.md @@ -1,187 +1,833 @@ -

- nvim-treesitter -

+
+

nvim-treesitter

+

+ + Matrix 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/issues/4767). +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.9.2** or later ([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 `:h 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" (the listed parsers MUST always be installed) + ensure_installed = { "c", "lua", "vim", "vimdoc", "query", "markdown", "markdown_inline" }, + + -- 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 (or "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 = { + 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] [ada](https://github.com/briot/tree-sitter-ada) (maintained by @briot) +- [x] [agda](https://github.com/tree-sitter/tree-sitter-agda) (maintained by @Decodetalkers) +- [x] [angular](https://github.com/dlvandenberg/tree-sitter-angular) (experimental, maintained by @dlvandenberg) +- [x] [apex](https://github.com/aheber/tree-sitter-sfapex) (maintained by @aheber, @xixiaofinland) +- [x] [arduino](https://github.com/ObserverOfTime/tree-sitter-arduino) (maintained by @ObserverOfTime) +- [x] [asm](https://github.com/RubixDev/tree-sitter-asm) (maintained by @RubixDev) +- [x] [astro](https://github.com/virchau13/tree-sitter-astro) (maintained by @virchau13) +- [x] [authzed](https://github.com/mleonidas/tree-sitter-authzed) (maintained by @mattpolzin) +- [ ] [awk](https://github.com/Beaglefoot/tree-sitter-awk) +- [x] [bash](https://github.com/tree-sitter/tree-sitter-bash) (maintained by @TravonteD) +- [x] [bass](https://github.com/vito/tree-sitter-bass) (maintained by @amaanq) +- [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] [bicep](https://github.com/amaanq/tree-sitter-bicep) (maintained by @amaanq) +- [x] [bitbake](https://github.com/amaanq/tree-sitter-bitbake) (maintained by @amaanq) +- [x] [blueprint](https://gitlab.com/gabmus/tree-sitter-blueprint.git) (experimental, maintained by @gabmus) +- [x] [bp](https://github.com/ambroisie/tree-sitter-bp) (maintained by @ambroisie) +- [x] [c](https://github.com/tree-sitter/tree-sitter-c) (maintained by @amaanq) +- [x] [c_sharp](https://github.com/tree-sitter/tree-sitter-c-sharp) (maintained by @amaanq) +- [x] [cairo](https://github.com/amaanq/tree-sitter-cairo) (maintained by @amaanq) +- [x] [capnp](https://github.com/amaanq/tree-sitter-capnp) (maintained by @amaanq) +- [x] [chatito](https://github.com/ObserverOfTime/tree-sitter-chatito) (maintained by @ObserverOfTime) +- [x] [clojure](https://github.com/sogaiu/tree-sitter-clojure) (maintained by @NoahTheDuke) +- [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] [corn](https://github.com/jakestanger/tree-sitter-corn) (maintained by @jakestanger) +- [x] [cpon](https://github.com/amaanq/tree-sitter-cpon) (maintained by @amaanq) +- [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] [csv](https://github.com/amaanq/tree-sitter-csv) (maintained by @amaanq) +- [x] [cuda](https://github.com/theHamsta/tree-sitter-cuda) (maintained by @theHamsta) +- [x] [cue](https://github.com/eonpatapon/tree-sitter-cue) (maintained by @amaanq) +- [x] [d](https://github.com/gdamore/tree-sitter-d) (maintained by @amaanq) +- [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] [dhall](https://github.com/jbellerb/tree-sitter-dhall) (maintained by @amaanq) +- [x] [diff](https://github.com/the-mikedavis/tree-sitter-diff) (maintained by @gbprod) +- [x] [disassembly](https://github.com/ColinKennedy/tree-sitter-disassembly) (maintained by @ColinKennedy) +- [x] [djot](https://github.com/treeman/tree-sitter-djot) (maintained by @NoahTheDuke) +- [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] [doxygen](https://github.com/amaanq/tree-sitter-doxygen) (maintained by @amaanq) +- [x] [dtd](https://github.com/tree-sitter-grammars/tree-sitter-xml) (maintained by @ObserverOfTime) +- [x] [earthfile](https://github.com/glehmann/tree-sitter-earthfile) (maintained by @glehmann) +- [x] [ebnf](https://github.com/RubixDev/ebnf) (experimental, maintained by @RubixDev) +- [x] [editorconfig](https://github.com/ValdezFOmar/tree-sitter-editorconfig) (maintained by @ValdezFOmar) +- [x] [eds](https://github.com/uyha/tree-sitter-eds) (maintained by @uyha) +- [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) +- [x] [elm](https://github.com/elm-tooling/tree-sitter-elm) (maintained by @zweimach) +- [x] [elsa](https://github.com/glapa-grossklag/tree-sitter-elsa) (maintained by @glapa-grossklag, @amaanq) +- [x] [elvish](https://github.com/elves/tree-sitter-elvish) (maintained by @elves) +- [ ] [embedded_template](https://github.com/tree-sitter/tree-sitter-embedded-template) +- [x] [erlang](https://github.com/WhatsApp/tree-sitter-erlang) (maintained by @filmor) +- [x] [facility](https://github.com/FacilityApi/tree-sitter-facility) (maintained by @bryankenote) +- [x] [faust](https://github.com/khiner/tree-sitter-faust) (maintained by @khiner) +- [x] [fennel](https://github.com/alexmozaidze/tree-sitter-fennel) (maintained by @alexmozaidze) +- [x] [fidl](https://github.com/google/tree-sitter-fidl) (maintained by @chaopeng) +- [x] [firrtl](https://github.com/amaanq/tree-sitter-firrtl) (maintained by @amaanq) +- [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) +- [x] [forth](https://github.com/AlexanderBrevig/tree-sitter-forth) (maintained by @amaanq) +- [x] [fortran](https://github.com/stadelmanma/tree-sitter-fortran) (maintained by @amaanq) +- [x] [fsh](https://github.com/mgramigna/tree-sitter-fsh) (maintained by @mgramigna) +- [x] [fsharp](https://github.com/ionide/tree-sitter-fsharp) (maintained by @nsidorenco) +- [x] [func](https://github.com/amaanq/tree-sitter-func) (maintained by @amaanq) +- [x] [fusion](https://gitlab.com/jirgn/tree-sitter-fusion.git) (maintained by @jirgn) +- [x] [GAP system](https://github.com/gap-system/tree-sitter-gap) (maintained by @reiniscirpons) +- [x] [GAP system test files](https://github.com/gap-system/tree-sitter-gaptst) (maintained by @reiniscirpons) +- [x] [Godot (gdscript)](https://github.com/PrestonKnopp/tree-sitter-gdscript) (maintained by @PrestonKnopp) +- [x] [gdshader](https://github.com/GodOfAvacyn/tree-sitter-gdshader) (maintained by @godofavacyn) +- [x] [git_config](https://github.com/the-mikedavis/tree-sitter-git-config) (maintained by @amaanq) +- [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/gleam-lang/tree-sitter-gleam) (maintained by @amaanq) +- [x] [Glimmer and Ember](https://github.com/ember-tooling/tree-sitter-glimmer) (maintained by @NullVoxPopuli) +- [x] [glimmer_javascript](https://github.com/NullVoxPopuli/tree-sitter-glimmer-javascript) (maintained by @NullVoxPopuli) +- [x] [glimmer_typescript](https://github.com/NullVoxPopuli/tree-sitter-glimmer-typescript) (maintained by @NullVoxPopuli) +- [x] [glsl](https://github.com/theHamsta/tree-sitter-glsl) (maintained by @theHamsta) +- [x] [GN (Generate Ninja)](https://github.com/amaanq/tree-sitter-gn) (maintained by @amaanq) +- [x] [gnuplot](https://github.com/dpezto/tree-sitter-gnuplot) (maintained by @dpezto) +- [x] [go](https://github.com/tree-sitter/tree-sitter-go) (maintained by @theHamsta, @WinWisely268) +- [x] [goctl](https://github.com/chaozwn/tree-sitter-goctl) (maintained by @chaozwn) +- [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] [gosum](https://github.com/amaanq/tree-sitter-go-sum) (maintained by @amaanq) +- [x] [gotmpl](https://github.com/ngalaiko/tree-sitter-go-template) (maintained by @qvalentin) +- [x] [gowork](https://github.com/omertuc/tree-sitter-go-work) (maintained by @omertuc) +- [x] [gpg](https://github.com/ObserverOfTime/tree-sitter-gpg-config) (maintained by @ObserverOfTime) +- [x] [graphql](https://github.com/bkegley/tree-sitter-graphql) (maintained by @bkegley) +- [x] [gren](https://github.com/MaeBrooks/tree-sitter-gren) (maintained by @MaeBrooks) +- [x] [groovy](https://github.com/murtaza64/tree-sitter-groovy) (maintained by @murtaza64) +- [x] [gstlaunch](https://github.com/theHamsta/tree-sitter-gstlaunch) (maintained by @theHamsta) +- [ ] [hack](https://github.com/slackhq/tree-sitter-hack) +- [x] [hare](https://github.com/amaanq/tree-sitter-hare) (maintained by @amaanq) +- [x] [haskell](https://github.com/tree-sitter/tree-sitter-haskell) (maintained by @mrcjkb) +- [x] [haskell_persistent](https://github.com/MercuryTechnologies/tree-sitter-haskell-persistent) (maintained by @lykahb) +- [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] [helm](https://github.com/ngalaiko/tree-sitter-go-template) (maintained by @qvalentin) +- [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] [hlsplaylist](https://github.com/Freed-Wu/tree-sitter-hlsplaylist) (maintained by @Freed-Wu) +- [x] [hocon](https://github.com/antosha417/tree-sitter-hocon) (maintained by @antosha417) +- [x] [hoon](https://github.com/urbit-pilled/tree-sitter-hoon) (experimental, maintained by @urbit-pilled) +- [x] [html](https://github.com/tree-sitter/tree-sitter-html) (maintained by @TravonteD) +- [x] [htmldjango](https://github.com/interdependence/tree-sitter-htmldjango) (experimental, maintained by @ObserverOfTime) +- [x] [http](https://github.com/rest-nvim/tree-sitter-http) (maintained by @amaanq, @NTBBloodbath) +- [x] [hurl](https://github.com/pfeiferj/tree-sitter-hurl) (maintained by @pfeiferj) +- [x] [hyprlang](https://github.com/luckasRanarison/tree-sitter-hyprlang) (maintained by @luckasRanarison) +- [x] [idl](https://github.com/cathaysia/tree-sitter-idl) (maintained by @cathaysia) +- [x] [ini](https://github.com/justinmk/tree-sitter-ini) (experimental, maintained by @theHamsta) +- [x] [inko](https://github.com/inko-lang/tree-sitter-inko) (maintained by @yorickpeterse) +- [x] [ispc](https://github.com/fab4100/tree-sitter-ispc) (maintained by @fab4100) +- [x] [janet_simple](https://github.com/sogaiu/tree-sitter-janet-simple) (maintained by @sogaiu) +- [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] [just](https://github.com/IndianBoy42/tree-sitter-just) (maintained by @Hubro) +- [x] [kconfig](https://github.com/amaanq/tree-sitter-kconfig) (maintained by @amaanq) +- [x] [kdl](https://github.com/amaanq/tree-sitter-kdl) (maintained by @amaanq) +- [x] [kotlin](https://github.com/fwcd/tree-sitter-kotlin) (maintained by @SalBakraa) +- [x] [koto](https://github.com/koto-lang/tree-sitter-koto) (maintained by @irh) +- [x] [kusto](https://github.com/Willem-J-an/tree-sitter-kusto) (maintained by @Willem-J-an) +- [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] [leo](https://github.com/r001/tree-sitter-leo) (maintained by @r001) +- [x] [linkerscript](https://github.com/amaanq/tree-sitter-linkerscript) (maintained by @amaanq) +- [x] [liquid](https://github.com/hankthetank27/tree-sitter-liquid) (maintained by @hankthetank27) +- [x] [liquidsoap](https://github.com/savonet/tree-sitter-liquidsoap) (maintained by @toots) +- [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] [luadoc](https://github.com/amaanq/tree-sitter-luadoc) (maintained by @amaanq) +- [x] [lua patterns](https://github.com/amaanq/tree-sitter-luap) (maintained by @amaanq) +- [x] [luau](https://github.com/amaanq/tree-sitter-luau) (maintained by @amaanq) +- [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 (basic highlighting)](https://github.com/MDeiml/tree-sitter-markdown) (experimental, maintained by @MDeiml) +- [x] [markdown_inline (needed for full highlighting)](https://github.com/MDeiml/tree-sitter-markdown) (experimental, maintained by @MDeiml) +- [x] [matlab](https://github.com/acristoffers/tree-sitter-matlab) (maintained by @acristoffers) +- [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) +- [x] [mlir](https://github.com/artagnon/tree-sitter-mlir) (experimental, maintained by @artagnon) +- [x] [muttrc](https://github.com/neomutt/tree-sitter-muttrc) (maintained by @Freed-Wu) +- [x] [nasm](https://github.com/naclsn/tree-sitter-nasm) (maintained by @ObserverOfTime) +- [x] [nginx](https://github.com/opa-oz/tree-sitter-nginx) (maintained by @opa-oz) +- [ ] [nickel](https://github.com/nickel-lang/tree-sitter-nickel) +- [x] [nim](https://github.com/alaviss/tree-sitter-nim) (maintained by @aMOPel) +- [x] [nim_format_string](https://github.com/aMOPel/tree-sitter-nim-format-string) (maintained by @aMOPel) +- [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] [nqc](https://github.com/amaanq/tree-sitter-nqc) (maintained by @amaanq) +- [x] [objc](https://github.com/amaanq/tree-sitter-objc) (maintained by @amaanq) +- [x] [objdump](https://github.com/ColinKennedy/tree-sitter-objdump) (maintained by @ColinKennedy) +- [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) +- [x] [odin](https://github.com/amaanq/tree-sitter-odin) (maintained by @amaanq) +- [ ] [org](https://github.com/milisims/tree-sitter-org) +- [x] [pascal](https://github.com/Isopod/tree-sitter-pascal) (maintained by @Isopod) +- [x] [passwd](https://github.com/ath3/tree-sitter-passwd) (maintained by @amaanq) +- [x] [pem](https://github.com/ObserverOfTime/tree-sitter-pem) (maintained by @ObserverOfTime) +- [x] [perl](https://github.com/tree-sitter-perl/tree-sitter-perl) (maintained by @RabbiVeesh, @LeoNerd) +- [x] [php](https://github.com/tree-sitter/tree-sitter-php) (maintained by @tk-shirasaka, @calebdw) +- [x] [php_only](https://github.com/tree-sitter/tree-sitter-php) (maintained by @tk-shirasaka, @calebdw) +- [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] [po](https://github.com/erasin/tree-sitter-po) (maintained by @amaanq) +- [x] [pod](https://github.com/tree-sitter-perl/tree-sitter-pod) (maintained by @RabbiVeesh, @LeoNerd) +- [x] [Path of Exile item filter](https://github.com/ObserverOfTime/tree-sitter-poe-filter) (experimental, maintained by @ObserverOfTime) +- [x] [pony](https://github.com/amaanq/tree-sitter-pony) (maintained by @amaanq, @mfelsche) +- [x] [powershell](https://github.com/airbus-cert/tree-sitter-powershell) (maintained by @L2jLiga) +- [x] [printf](https://github.com/ObserverOfTime/tree-sitter-printf) (maintained by @ObserverOfTime) +- [x] [prisma](https://github.com/victorhqc/tree-sitter-prisma) (maintained by @elianiva) +- [x] [problog](https://github.com/foxyseta/tree-sitter-prolog) (maintained by @foxyseta) +- [x] [prolog](https://github.com/foxyseta/tree-sitter-prolog) (maintained by @foxyseta) +- [x] [promql](https://github.com/MichaHoffmann/tree-sitter-promql) (maintained by @MichaHoffmann) +- [x] [properties](https://github.com/tree-sitter-grammars/tree-sitter-properties) (maintained by @ObserverOfTime) +- [x] [proto](https://github.com/treywood/tree-sitter-proto) (maintained by @treywood) +- [x] [prql](https://github.com/PRQL/tree-sitter-prql) (maintained by @matthias-Q) +- [x] [psv](https://github.com/amaanq/tree-sitter-csv) (maintained by @amaanq) +- [x] [pug](https://github.com/zealot128/tree-sitter-pug) (experimental, maintained by @zealot128) +- [x] [puppet](https://github.com/amaanq/tree-sitter-puppet) (maintained by @amaanq) +- [x] [purescript](https://github.com/postsolar/tree-sitter-purescript) (maintained by @postsolar) +- [x] [PyPA manifest](https://github.com/ObserverOfTime/tree-sitter-pymanifest) (maintained by @ObserverOfTime) +- [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] [qmldir](https://github.com/Decodetalkers/tree-sitter-qmldir) (maintained by @amaanq) +- [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 @ribru17) +- [ ] [racket](https://github.com/6cdh/tree-sitter-racket) +- [x] [ralph](https://github.com/alephium/tree-sitter-ralph) (maintained by @tdroxler) +- [x] [rasi](https://github.com/Fymyte/tree-sitter-rasi) (maintained by @Fymyte) +- [x] [rbs](https://github.com/joker1007/tree-sitter-rbs) (maintained by @joker1007) +- [x] [re2c](https://github.com/amaanq/tree-sitter-re2c) (maintained by @amaanq) +- [x] [readline](https://github.com/ribru17/tree-sitter-readline) (maintained by @ribru17) +- [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] [pip requirements](https://github.com/ObserverOfTime/tree-sitter-requirements) (maintained by @ObserverOfTime) +- [x] [rescript](https://github.com/rescript-lang/tree-sitter-rescript) (maintained by @ribru17) +- [x] [rnoweb](https://github.com/bamonroe/tree-sitter-rnoweb) (maintained by @bamonroe) +- [x] [robot](https://github.com/Hubro/tree-sitter-robot) (maintained by @Hubro) +- [x] [robots](https://github.com/opa-oz/tree-sitter-robots-txt) (maintained by @opa-oz) +- [x] [roc](https://github.com/faldor20/tree-sitter-roc) (maintained by @nat-418) +- [x] [ron](https://github.com/amaanq/tree-sitter-ron) (maintained by @amaanq) +- [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 @amaanq) +- [x] [scala](https://github.com/tree-sitter/tree-sitter-scala) (maintained by @stevanmilic) +- [x] [scfg](https://github.com/rockorager/tree-sitter-scfg) (maintained by @WhyNotHugo) +- [ ] [scheme](https://github.com/6cdh/tree-sitter-scheme) +- [x] [scss](https://github.com/serenadeai/tree-sitter-scss) (maintained by @elianiva) +- [x] [sflog](https://github.com/aheber/tree-sitter-sfapex) (maintained by @aheber, @xixiaofinland) +- [x] [slang](https://github.com/theHamsta/tree-sitter-slang) (experimental, maintained by @theHamsta) +- [x] [slint](https://github.com/slint-ui/tree-sitter-slint) (maintained by @hunger) +- [x] [smali](https://github.com/tree-sitter-grammars/tree-sitter-smali) (maintained by @amaanq) +- [x] [smithy](https://github.com/indoorvivants/tree-sitter-smithy) (maintained by @amaanq, @keynmol) +- [ ] [snakemake](https://github.com/osthomas/tree-sitter-snakemake) (experimental) +- [x] [solidity](https://github.com/JoranHonig/tree-sitter-solidity) (maintained by @amaanq) +- [x] [soql](https://github.com/aheber/tree-sitter-sfapex) (maintained by @aheber, @xixiaofinland) +- [x] [sosl](https://github.com/aheber/tree-sitter-sfapex) (maintained by @aheber, @xixiaofinland) +- [x] [sourcepawn](https://github.com/nilshelmig/tree-sitter-sourcepawn) (maintained by @Sarrus1) +- [x] [sparql](https://github.com/GordianDziwis/tree-sitter-sparql) (maintained by @GordianDziwis) +- [x] [sql](https://github.com/derekstride/tree-sitter-sql) (maintained by @derekstride) +- [x] [squirrel](https://github.com/amaanq/tree-sitter-squirrel) (maintained by @amaanq) +- [x] [ssh_config](https://github.com/ObserverOfTime/tree-sitter-ssh-config) (maintained by @ObserverOfTime) +- [x] [starlark](https://github.com/amaanq/tree-sitter-starlark) (maintained by @amaanq) +- [x] [strace](https://github.com/sigmaSd/tree-sitter-strace) (maintained by @amaanq) +- [x] [styled](https://github.com/mskelton/tree-sitter-styled) (maintained by @mskelton) +- [x] [supercollider](https://github.com/madskjeldgaard/tree-sitter-supercollider) (maintained by @madskjeldgaard) +- [x] [superhtml](https://github.com/kristoff-it/superhtml) (maintained by @rockorager) +- [x] [surface](https://github.com/connorlay/tree-sitter-surface) (maintained by @connorlay) +- [x] [svelte](https://github.com/tree-sitter-grammars/tree-sitter-svelte) (maintained by @amaanq) +- [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] [systemtap](https://github.com/ok-ryoko/tree-sitter-systemtap) (maintained by @ok-ryoko) +- [x] [t32](https://gitlab.com/xasc/tree-sitter-t32.git) (maintained by @xasc) +- [x] [tablegen](https://github.com/amaanq/tree-sitter-tablegen) (maintained by @amaanq) +- [x] [tact](https://github.com/tact-lang/tree-sitter-tact) (maintained by @novusnota) +- [x] [tcl](https://github.com/tree-sitter-grammars/tree-sitter-tcl) (maintained by @lewis6991) +- [x] [teal](https://github.com/euclidianAce/tree-sitter-teal) (maintained by @euclidianAce) +- [x] [templ](https://github.com/vrischmann/tree-sitter-templ) (maintained by @vrischmann) +- [x] [terraform](https://github.com/MichaHoffmann/tree-sitter-hcl) (maintained by @MichaHoffmann) +- [x] [textproto](https://github.com/PorterAtGoogle/tree-sitter-textproto) (maintained by @Porter) +- [x] [thrift](https://github.com/duskmoon314/tree-sitter-thrift) (maintained by @amaanq, @duskmoon314) +- [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] [tmux](https://github.com/Freed-Wu/tree-sitter-tmux) (maintained by @Freed-Wu) +- [x] [todotxt](https://github.com/arnarg/tree-sitter-todotxt) (experimental, maintained by @arnarg) +- [x] [toml](https://github.com/tree-sitter-grammars/tree-sitter-toml) (maintained by @tk-shirasaka) +- [x] [tsv](https://github.com/amaanq/tree-sitter-csv) (maintained by @amaanq) +- [x] [tsx](https://github.com/tree-sitter/tree-sitter-typescript) (maintained by @steelsojka) +- [x] [turtle](https://github.com/GordianDziwis/tree-sitter-turtle) (maintained by @GordianDziwis) +- [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] [typespec](https://github.com/happenslol/tree-sitter-typespec) (maintained by @happenslol) +- [x] [typoscript](https://github.com/Teddytrombone/tree-sitter-typoscript) (maintained by @Teddytrombone) +- [x] [typst](https://github.com/uben0/tree-sitter-typst) (maintained by @uben0, @RaafatTurki) +- [x] [udev](https://github.com/ObserverOfTime/tree-sitter-udev) (maintained by @ObserverOfTime) +- [x] [ungrammar](https://github.com/Philipp-M/tree-sitter-ungrammar) (maintained by @Philipp-M, @amaanq) +- [x] [unison](https://github.com/kylegoetz/tree-sitter-unison) (maintained by @tapegram) +- [x] [usd](https://github.com/ColinKennedy/tree-sitter-usd) (maintained by @ColinKennedy) +- [x] [uxn tal](https://github.com/amaanq/tree-sitter-uxntal) (maintained by @amaanq) +- [x] [v](https://github.com/vlang/v-analyzer) (maintained by @kkharji, @amaanq) +- [x] [vala](https://github.com/vala-lang/tree-sitter-vala) (maintained by @Prince781) +- [x] [vento](https://github.com/ventojs/tree-sitter-vento) (maintained by @wrapperup, @oscarotero) +- [x] [verilog](https://github.com/gmlarumbe/tree-sitter-systemverilog) (maintained by @zhangwwpeng) +- [x] [vhdl](https://github.com/jpt13653903/tree-sitter-vhdl) (maintained by @jpt13653903) +- [x] [vhs](https://github.com/charmbracelet/tree-sitter-vhs) (maintained by @caarlos0) +- [x] [vim](https://github.com/neovim/tree-sitter-vim) (maintained by @clason) +- [x] [vimdoc](https://github.com/neovim/tree-sitter-vimdoc) (maintained by @clason) +- [x] [vrl](https://github.com/belltoy/tree-sitter-vrl) (maintained by @belltoy) +- [x] [vue](https://github.com/tree-sitter-grammars/tree-sitter-vue) (maintained by @WhyNotHugo, @lucario387) +- [x] [wgsl](https://github.com/szebniok/tree-sitter-wgsl) (maintained by @szebniok) +- [x] [wgsl_bevy](https://github.com/theHamsta/tree-sitter-wgsl-bevy) (maintained by @theHamsta) +- [x] [wing](https://github.com/winglang/tree-sitter-wing) (maintained by @gshpychka, @MarkMcCulloh) +- [x] [wit](https://github.com/liamwh/tree-sitter-wit) (maintained by @liamwh) +- [x] [xcompose](https://github.com/ObserverOfTime/tree-sitter-xcompose) (maintained by @ObserverOfTime) +- [x] [xml](https://github.com/tree-sitter-grammars/tree-sitter-xml) (maintained by @ObserverOfTime) +- [x] [xresources](https://github.com/ValdezFOmar/tree-sitter-xresources) (maintained by @ValdezFOmar) +- [x] [yaml](https://github.com/tree-sitter-grammars/tree-sitter-yaml) (maintained by @amaanq) +- [x] [yang](https://github.com/Hubro/tree-sitter-yang) (maintained by @Hubro) +- [x] [yuck](https://github.com/Philipp-M/tree-sitter-yuck) (maintained by @Philipp-M, @amaanq) +- [x] [zathurarc](https://github.com/Freed-Wu/tree-sitter-zathurarc) (maintained by @Freed-Wu) +- [x] [zig](https://github.com/tree-sitter-grammars/tree-sitter-zig) (maintained by @amaanq) +- [x] [ziggy](https://github.com/kristoff-it/ziggy) (maintained by @rockorager) +- [x] [ziggy_schema](https://github.com/kristoff-it/ziggy) (maintained by @rockorager) + -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", -- set to `false` to disable one of the mappings + 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 (implemented in Neovim itself, see `:h vim.treesitter.foldexpr()`). To enable it for the current window, set + +```lua +vim.wo.foldmethod = 'expr' +vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()' +``` + +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 prepended to the +`runtimepath`. For example: + +```lua + -- It MUST be at the beginning of runtimepath. Otherwise the parsers from Neovim itself + -- is loaded that may not be compatible with the queries from the 'nvim-treesitter' plugin. + vim.opt.runtimepath:prepend("/some/path/to/store/parsers") + + require'nvim-treesitter.configs'.setup { + parser_install_dir = "/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"}, -- note that some parsers also require src/scanner.c or src/scanner.cc + -- 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 use `vim.treesitter.language.register()`: ```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' }) +vim.treesitter.language.register('python', 'someft') -- the someft filetype will use the python parser and queries. ``` +Note this requires Nvim v0.9. + +4. 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`. + +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()`]() to add a custom detection rule. -3. Start `nvim` and `:TSInstall zimbu`. - ->[!IMPORTANT] -> If the parser requires an external scanner, this must be written in C. - -### 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). + +The first query file on `runtimepath` will be used (see `:h treesitter-query`). +If you want to make a query on the user config extend other queries instead of +replacing them, see `:h treesitter-query-modeline-extends`. + +If you want to completely override a query, you can use `:h vim.treesitter.query.set()`. +For example, to override the `injections` queries from `c` with your own: + +```lua +vim.treesitter.query.set("c", "injections", "(comment) @comment") +``` + +Note: when using `query.set()`, 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 { + -- + -- +} +``` + +#### Using an existing parser for another filetype + +For example, to use the `bash` tree-sitter to highlight file with +`filetype=apkbuild`, use: + +```lua +vim.treesitter.language.register("bash", "apkbuild") +``` + +The `bash` tree-sitter must be installed following the usual procedure [as +described above](#language-parsers). 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-luarocks.template b/contrib/nvim-treesitter-luarocks.template new file mode 100644 index 000000000..8109f5f2b --- /dev/null +++ b/contrib/nvim-treesitter-luarocks.template @@ -0,0 +1,41 @@ +local git_ref = '$git_ref' +local modrev = '$modrev' +local specrev = '-1' + +local repo_url = '$repo_url' + +rockspec_format = '3.0' +package = '$package' +version = modrev .. specrev + +description = { + summary = 'Nvim Treesitter configurations and abstraction layer', + detailed = $detailed_description, + labels = { 'neovim' }, + homepage = 'https://github.com/nvim-treesitter/nvim-treesitter', + license = 'Apache-2.0', +} + +dependencies = { + 'lua >= 5.1', +} + +-- source = file:///. + +source = { + url = repo_url .. '/archive/' .. git_ref .. '.zip', + dir = '$repo_name-' .. '$archive_dir_suffix', +} + +build = { + type = 'make', + build_pass = false, + install_variables = { + INST_PREFIX='$(PREFIX)', + INST_BINDIR='$(BINDIR)', + INST_LIBDIR='$(LIBDIR)', + INST_LUADIR='$(LUADIR)', + INST_CONFDIR='$(CONFDIR)', + }, + copy_directories = $copy_directories, +} diff --git a/contrib/nvim-treesitter-scm-1.rockspec b/contrib/nvim-treesitter-scm-1.rockspec new file mode 100644 index 000000000..a901c5b12 --- /dev/null +++ b/contrib/nvim-treesitter-scm-1.rockspec @@ -0,0 +1,36 @@ +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', +} + +source = { + url = 'git://github.com/nvim-treesitter/nvim-treesitter', +} + +build = { + type = 'make', + install_variables = { + INST_PREFIX='$(PREFIX)', + INST_BINDIR='$(BINDIR)', + INST_LIBDIR='$(LIBDIR)', + INST_LUADIR='$(LUADIR)', + INST_CONFDIR='$(CONFDIR)', + }, + copy_directories = { + 'autoload', + 'doc', + 'plugin', + 'queries' + } +} diff --git a/doc/nvim-treesitter.txt b/doc/nvim-treesitter.txt index e6a67f398..f7a91b849 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,578 @@ 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, + }, + } + vim.opt.runtimepath:append("/some/path/to/store/parsers") +< + +See |nvim-treesitter-modules| for a list of all available modules and its options. + +============================================================================== +MODULES *nvim-treesitter-modules* + +|nvim-treesitter| provides several functionalities via modules (and submodules), +each module makes use of the query files defined for each language, + +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. + +> + require'nvim-treesitter.configs'.setup { + -- Modules and its options go here + highlight = { enable = true }, + incremental_selection = { enable = true }, + textobjects = { enable = true }, + } +< + +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. + +> + require'nvim-treesitter.configs'.setup { + highlight = { + enable = true, + disable = { "cpp", "lua" }, + }, + } +< + +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: + +> + 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, + }, + } +< + +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. + +External plugins can provide their own modules with their own options, +those can also be configured using the `nvim-treesitter.configs.setup` +function. + +------------------------------------------------------------------------------ +HIGHLIGHT *nvim-treesitter-highlight-mod* + +Consistent syntax highlighting. + +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, + }, + } +< + +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 + }, } -NOTE: You do not need to call `setup` to use this plugin with the default -settings! +`@indent` *nvim-treesitter-indentation-queries* +Queries can use the following captures: `@indent.begin` and `@indent.dedent`, +`@indent.branch`, `@indent.end` or `@indent.align`. An `@indent.ignore` capture tells +treesitter to ignore indentation and a `@indent.zero` capture sets +the indentation to 0. -Parsers and queries can then be installed with >lua - require'nvim-treesitter'.install { 'rust', 'javascript', 'zig' } +`@indent.begin` *nvim-treesitter-indentation-indent.begin* +The `@indent.begin` specifies that the next line should be indented. Multiple +indents on the same line get collapsed. Eg. + +> + ( + (if_statement) + (ERROR "else") @indent.begin + ) < -To check installed parsers and queries, use `:checkhealth nvim-treesitter`. +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. -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, - }) +eg for python: +> + ((if_statement) @indent.begin + (#set! indent.immediate 1)) < -============================================================================== -COMMANDS *nvim-treesitter-commands* -:TSInstall {language} *:TSInstall* +Will allow: +> + if True: + # Auto indent to here -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. +`@indent.end` *nvim-treesitter-indentation-indent.end* +An `@indent.end` capture is used to specify that the indented region ends and +any text subsequent to the capture should be dedented. -:TSInstallFromGrammar {language} *:TSInstallFromGrammar* +`@indent.branch` *nvim-treesitter-indentation-indent.branch* +An `@indent.branch` capture is used to specify that a dedented region starts +at the line including the captured nodes. -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). +`@indent.dedent` *nvim-treesitter-indentation-indent.dedent* +A `@indent.dedent` capture specifies dedenting starting on the next line. +> +`@indent.align` *nvim-treesitter-indentation-aligned_indent.align* +Aligned indent blocks may be specified with the `@indent.align` capture. +This permits -:TSUpdate [{language}] *:TSUpdate* +> + foo(a, + b, + c) +< +As well as +> + foo( + a, + b, + c) +< +and finally +> + foo( + a, + b, + c + ) +< +To specify the delimiters to use `indent.open_delimiter` and +`indent.close_delimiter` should be used. Eg. +> + ((argument_list) @indent.align + (#set! indent.open_delimiter "(") + (#set! indent.close_delimiter ")")) +< -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. +For some languages the last line of an `indent.align` block must not be +the same indent as the natural next line. -Note: It is recommended to add this command as a build step in your plugin -manager. +For example in python: -:TSUninstall {language} *:TSUninstall* +> + if (a > b and + c < d): + pass -Deletes the parser for one or more {language}, or all parsers with `all`. +Is not correct, whereas +> + if (a > b and + c < d): + pass -:TSLog *:TSLog* +Would be correctly indented. This behavior may be chosen using +`indent.avoid_last_matching_next`. Eg. -Shows all messages from previous install, update, or uninstall operations. +> + (if_statement + condition: (parenthesized_expression) @indent.align + (#set! indent.open_delimiter "(") + (#set! indent.close_delimiter ")") + (#set! indent.avoid_last_matching_next 1) + ) +< +Could be used to specify 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. ============================================================================== -API *nvim-treesitter-api* +COMMANDS *nvim-treesitter-commands* -setup({opts}) *nvim-treesitter.setup()* + *:TSInstall* +:TSInstall {language} ...~ - Configure installation options. Needs to be specified before any - installation operation. +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} ...~ - Note: You only need to call `setup` if you want to set non-default - options! +Perform the |:TSInstall| operation synchronously. - 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|. + *:TSInstallInfo* +:TSInstallInfo~ -install({languages} [, {opts}]) *nvim-treesitter.install()* +List information about currently installed parsers - Download, compile, and install the specified treesitter parsers and copy - the corresponding queries to a directory on |runtimepath|, enabling their - use in Neovim. + *:TSUpdate* +:TSUpdate {language} ...~ - 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 +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 < - 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()* + *:TSEditQuery* +:TSEditQuery {query-group} [{lang}]~ - Remove the parser and queries for the specified language(s). +Edit the query file for a {query-group} (e.g. highlights, locals) for given +{lang}. If there are multiple files, 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. - 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. + *:TSEditQueryUserAfter* +:TSEditQueryUserAfter {query-group} [{lang}]~ -update([{languages}, {opts}]) *nvim-treesitter.update()* +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. - Update the parsers and queries if older than the revision specified in the - manifest. +============================================================================== +UTILS *nvim-treesitter-utils* - 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 +Nvim treesitter has some wrapper functions that you can retrieve with: +> + local ts_utils = require 'nvim-treesitter.ts_utils' < - 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. +Methods + *ts_utils.get_node_at_cursor* +get_node_at_cursor(winnr)~ -indentexpr() *nvim-treesitter.indentexpr()* +`winnr` will be 0 if nil. +Returns the node under the cursor. - Used to enable treesitter indentation for a language via >lua - vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" + *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.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, _node) return line:gsub('%s*[%[%(%{]*%s*$', '') end, + separator = ' -> ', + allow_duplicates = false + } < -get_available([{tier}]) *nvim-treesitter.get_available()* +- `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 it removes opening brackets and spaces from end. Takes two arguments: + the text of the line in question, and the corresponding treesitter node. +- `separator` - Separator between nodes. +- `allow_duplicates` - Whether or not to remove duplicate components. - Return list of languages available for installation. + *nvim_treesitter#foldexpr()* +nvim_treesitter#foldexpr()~ - Parameters: ~ - • {tier} `(integer?)` Only return languages of specified {tier} (`1`: - stable, `2`: unstable, `3`: unmaintained, `4`: unsupported) - -get_installed([{type}]) *nvim-treesitter.get_installed()* - - Return list of languages installed via `nvim-treesitter`. - - 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) +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() < - Parameters: ~ - • {type} `('queries'|parsers'?)` If specified, only show languages with - installed queries or parsers, respectively. + +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, hitting `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..627e8e6bf --- /dev/null +++ b/lockfile.json @@ -0,0 +1,905 @@ +{ + "ada": { + "revision": "e8e2515465cc2d7c444498e68bdb9f1d86767f95" + }, + "agda": { + "revision": "6516cfec35479d62c0ad3c8e7e546a9774b489fd" + }, + "angular": { + "revision": "745d3c65c2294aca1110b6b6ad6805124be605c9" + }, + "apex": { + "revision": "46d4a12e4e90b10a575b7b16ea3b6ead50322074" + }, + "arduino": { + "revision": "415ebc8f75eb02a748faa03f5af199f08ced120f" + }, + "asm": { + "revision": "55b2b913f1e71136027d6fce8212e760c64f3532" + }, + "astro": { + "revision": "4be180759ec13651f72bacee65fa477c64222a1a" + }, + "authzed": { + "revision": "1dec7e1af96c56924e3322cd85fdce15d0a31d00" + }, + "awk": { + "revision": "553fdc4afb3b603332c3f4baf50c711506f4e797" + }, + "bash": { + "revision": "597a5ed6ed4d932fd44697feec988f977081ae59" + }, + "bass": { + "revision": "28dc7059722be090d04cd751aed915b2fee2f89a" + }, + "beancount": { + "revision": "01c0da29e0fc7130420a09d939ecc524e09b6ba6" + }, + "bibtex": { + "revision": "ccfd77db0ed799b6c22c214fe9d2937f47bc8b34" + }, + "bicep": { + "revision": "0092c7d1bd6bb22ce0a6f78497d50ea2b87f19c0" + }, + "bitbake": { + "revision": "a5d04fdb5a69a02b8fa8eb5525a60dfb5309b73b" + }, + "blueprint": { + "revision": "60ba73739c6083c693d86a1a7cf039c07eb4ed59" + }, + "bp": { + "revision": "4e60cf3c2e613625c06f6f85540b3631e2d06cd3" + }, + "c": { + "revision": "79284a14a0d7e4495b095b38acdd8a27acbe870e" + }, + "c_sharp": { + "revision": "3a85187e0a9e8db01dec6b3eb2f4e7cdfecc9d88" + }, + "cairo": { + "revision": "6238f609bea233040fe927858156dee5515a0745" + }, + "capnp": { + "revision": "7b0883c03e5edd34ef7bcf703194204299d7099f" + }, + "chatito": { + "revision": "a461f20dedb43905febb12c1635bc7d2e43e96f0" + }, + "clojure": { + "revision": "f4236d4da8aa92bc105d9c118746474c608e6af7" + }, + "cmake": { + "revision": "e409ae33f00e04cde30f2bcffb979caf1a33562a" + }, + "comment": { + "revision": "3555706cef8b98d3e4c7379d7260548ff03ad363" + }, + "commonlisp": { + "revision": "bf2a65b1c119898a1a17389e07f2a399c05cdc0c" + }, + "cooklang": { + "revision": "4ebe237c1cf64cf3826fc249e9ec0988fe07e58e" + }, + "corn": { + "revision": "464654742cbfd3a3de560aba120998f1d5dfa844" + }, + "cpon": { + "revision": "594289eadfec719198e560f9d7fd243c4db678d5" + }, + "cpp": { + "revision": "16bf9d2c451957aee976c982c2c668b1c0d12014" + }, + "css": { + "revision": "ccc4e2c4b30ddabc4b41c577ad0550b3cac4a74a" + }, + "csv": { + "revision": "7eb7297823605392d2bbcc4c09b1cd18d6fa9529" + }, + "cuda": { + "revision": "635e8aa3747823a0c4e9660c07cef76fe8d3ef93" + }, + "cue": { + "revision": "8a5f273bfa281c66354da562f2307c2d394b6c81" + }, + "d": { + "revision": "45e5f1e9d6de2c68591bc8e5ec662cf18e950b4a" + }, + "dart": { + "revision": "9ac03bb2154316624fb4c41fe0f372a5f1597b43" + }, + "devicetree": { + "revision": "16c9cb959675bc9bc4f4e5bebe473d511a12a06d" + }, + "dhall": { + "revision": "affb6ee38d629c9296749767ab832d69bb0d9ea8" + }, + "diff": { + "revision": "63439b5e6e35750aff1e53d9eecc663d369c54bc" + }, + "disassembly": { + "revision": "0229c0211dba909c5d45129ac784a3f4d49c243a" + }, + "djot": { + "revision": "886601b67d1f4690173a4925c214343c30704d32" + }, + "dockerfile": { + "revision": "087daa20438a6cc01fa5e6fe6906d77c869d19fe" + }, + "dot": { + "revision": "9ab85550c896d8b294d9b9ca1e30698736f08cea" + }, + "doxygen": { + "revision": "ccd998f378c3f9345ea4eeb223f56d7b84d16687" + }, + "dtd": { + "revision": "cd1316e476ec40da6ce1fb5749c9d7e6b4f1090c" + }, + "earthfile": { + "revision": "1d637f2002bb8b22d4c08d26ad2bfbc22916f3ce" + }, + "ebnf": { + "revision": "8e635b0b723c620774dfb8abf382a7f531894b40" + }, + "editorconfig": { + "revision": "777f774d6381f1bb84adffa02a4e476fb61486ae" + }, + "eds": { + "revision": "26d529e6cfecde391a03c21d1474eb51e0285805" + }, + "eex": { + "revision": "f742f2fe327463335e8671a87c0b9b396905d1d1" + }, + "elixir": { + "revision": "2ac7a0f81f0731d83068b2872c4a8fee39263a85" + }, + "elm": { + "revision": "27f502ed0a1cbd3c5912d284cc7934ee0d4cdddc" + }, + "elsa": { + "revision": "0a66b2b3f3c1915e67ad2ef9f7dbd2a84820d9d7" + }, + "elvish": { + "revision": "5e7210d945425b77f82cbaebc5af4dd3e1ad40f5" + }, + "embedded_template": { + "revision": "7e319b065c5864bac2fb68f7e14a338b919e8bb3" + }, + "erlang": { + "revision": "4095e9993acc89cb311ab1be8614c21b1cf768a4" + }, + "facility": { + "revision": "2d037f2f2bf668737f72e6be6eda4b7918b68d86" + }, + "faust": { + "revision": "f3b9274514b5f9bf6b0dd4a01c30f9cc15c58bc4" + }, + "fennel": { + "revision": "cfbfa478dc2dbef267ee94ae4323d9c886f45e94" + }, + "fidl": { + "revision": "0a8910f293268e27ff554357c229ba172b0eaed2" + }, + "firrtl": { + "revision": "8503d3a0fe0f9e427863cb0055699ff2d29ae5f5" + }, + "fish": { + "revision": "a78aef9abc395c600c38a037ac779afc7e3cc9e0" + }, + "foam": { + "revision": "04664b40c0dadb7ef37028acf3422c63271d377b" + }, + "forth": { + "revision": "90189238385cf636b9ee99ce548b9e5b5e569d48" + }, + "fortran": { + "revision": "4a593dda9cbc050a6686187249f8350ceea292ce" + }, + "fsh": { + "revision": "fad2e175099a45efbc98f000cc196d3674cc45e0" + }, + "fsharp": { + "revision": "971da5ff0266bfe4a6ecfb94616548032d6d1ba0" + }, + "func": { + "revision": "f780ca55e65e7d7360d0229331763e16c452fc98" + }, + "fusion": { + "revision": "19db2f47ba4c3a0f6238d4ae0e2abfca16e61dd6" + }, + "gap": { + "revision": "141b063335e85299bde3f61b4888d02d674a1abc" + }, + "gaptst": { + "revision": "e0723dc6136309b3d5904dad2c73ef71267428c1" + }, + "gdscript": { + "revision": "1f1e782fe2600f50ae57b53876505b8282388d77" + }, + "gdshader": { + "revision": "ffd9f958df13cae04593781d7d2562295a872455" + }, + "git_config": { + "revision": "9c2a1b7894e6d9eedfe99805b829b4ecd871375e" + }, + "git_rebase": { + "revision": "bff4b66b44b020d918d67e2828eada1974a966aa" + }, + "gitattributes": { + "revision": "41940e199ba5763abea1d21b4f717014b45f01ea" + }, + "gitcommit": { + "revision": "db0e0c4fb9095fdc42a7af34019c0616c071e9eb" + }, + "gitignore": { + "revision": "f4685bf11ac466dd278449bcfe5fd014e94aa504" + }, + "gleam": { + "revision": "57c9951b290c8084d7c60b0aee7a2b30986ea031" + }, + "glimmer": { + "revision": "da605af8c5999b43e6839b575eae5e6cafabb06f" + }, + "glimmer_javascript": { + "revision": "7e8ea8cf39fc360cb97bd253442cd48e4f7a9ce3" + }, + "glimmer_typescript": { + "revision": "4006128790efb58ca82a4492d8ef0983b260fc6a" + }, + "glsl": { + "revision": "66aec57f7119c7e8e40665b723cd7af5594f15ee" + }, + "gn": { + "revision": "bc06955bc1e3c9ff8e9b2b2a55b38b94da923c05" + }, + "gnuplot": { + "revision": "3c895f5d9c0b3a3c7e02383766b462c21913c000" + }, + "go": { + "revision": "df2ce2e206d2810bf010d73055055bfcff1b55aa" + }, + "goctl": { + "revision": "49c43532689fe1f53e8b9e009d0521cab02c432b" + }, + "godot_resource": { + "revision": "2ffb90de47417018651fc3b970e5f6b67214dc9d" + }, + "gomod": { + "revision": "3b01edce2b9ea6766ca19328d1850e456fde3103" + }, + "gosum": { + "revision": "e2ac513b2240c7ff1069ae33b2df29ce90777c11" + }, + "gotmpl": { + "revision": "ca52fbfc98366c585b84f4cb3745df49f33cd140" + }, + "gowork": { + "revision": "949a8a470559543857a62102c84700d291fc984c" + }, + "gpg": { + "revision": "f99323fb8f3f10b6c69db0c2f6d0a14bd7330675" + }, + "graphql": { + "revision": "5e66e961eee421786bdda8495ed1db045e06b5fe" + }, + "gren": { + "revision": "c06e272341363c5d8e19ac34bc7c56258a37e71b" + }, + "groovy": { + "revision": "0d8884514fe10c4fa47527d9a0284d207f38ddea" + }, + "gstlaunch": { + "revision": "549aef253fd38a53995cda1bf55c501174372bf7" + }, + "hack": { + "revision": "fca1e294f6dce8ec5659233a6a21f5bd0ed5b4f2" + }, + "hare": { + "revision": "4af5d82cf9ec39f67cb1db5b7a9269d337406592" + }, + "haskell": { + "revision": "70ea0757986ea58a0d39ddfcd9d791beadeb0f43" + }, + "haskell_persistent": { + "revision": "577259b4068b2c281c9ebf94c109bd50a74d5857" + }, + "hcl": { + "revision": "9e3ec9848f28d26845ba300fd73c740459b83e9b" + }, + "heex": { + "revision": "6dd0303acf7138dd2b9b432a229e16539581c701" + }, + "helm": { + "revision": "ca52fbfc98366c585b84f4cb3745df49f33cd140" + }, + "hjson": { + "revision": "02fa3b79b3ff9a296066da6277adfc3f26cbc9e0" + }, + "hlsl": { + "revision": "b309425a7ab4456605cfe78774b80f7e275ca87d" + }, + "hlsplaylist": { + "revision": "3bfda9271e3adb08d35f47a2102fe957009e1c55" + }, + "hocon": { + "revision": "c390f10519ae69fdb03b3e5764f5592fb6924bcc" + }, + "hoon": { + "revision": "a24c5a39d1d7e993a8bee913c8e8b6a652ca5ae8" + }, + "html": { + "revision": "c30792dee70aaa1910e66a39557a841b6e4386d5" + }, + "htmldjango": { + "revision": "ea71012d3fe14dd0b69f36be4f96bdfe9155ebae" + }, + "http": { + "revision": "231f1b1bafd12e46c8ed8c21dbbdd940d9f15e94" + }, + "hurl": { + "revision": "ff07a42d9ec95443b5c1b57ed793414bf7b79be5" + }, + "hyprlang": { + "revision": "6858695eba0e63b9e0fceef081d291eb352abce8" + }, + "idl": { + "revision": "5573b295410201ed22771776b34d636900eba368" + }, + "ini": { + "revision": "962568c9efa71d25720ab42c5d36e222626ef3a6" + }, + "inko": { + "revision": "6f9c072d023c3886aabcd8012274461b35d2d0a9" + }, + "ispc": { + "revision": "9b2f9aec2106b94b4e099fe75e73ebd8ae707c04" + }, + "janet_simple": { + "revision": "12bfab7db8a5f5b1d774ef84b5831acd34936071" + }, + "java": { + "revision": "b864ed97b9675e86de7c15a70c12e4c1ca85fbf9" + }, + "javascript": { + "revision": "c4ce9dc8e7e98ea25757ea26bfe9a022043ccd77" + }, + "jq": { + "revision": "13990f530e8e6709b7978503da9bc8701d366791" + }, + "jsdoc": { + "revision": "b2237872e528b8372ed008068f717db66c16a725" + }, + "json": { + "revision": "f2503f1c437fe24560876557868ac94c9cfd3216" + }, + "json5": { + "revision": "ab0ba8229d639ec4f3fa5f674c9133477f4b77bd" + }, + "jsonc": { + "revision": "02b01653c8a1c198ae7287d566efa86a135b30d5" + }, + "jsonnet": { + "revision": "ddd075f1939aed8147b7aa67f042eda3fce22790" + }, + "julia": { + "revision": "19f62656dc7f2ff3756a8ef3dcf9ab1c01a9eb58" + }, + "just": { + "revision": "6aee3d2f5b3a47286bae0916daaa6c7a217f6fa4" + }, + "kconfig": { + "revision": "486fea71f61ad9f3fd4072a118402e97fe88d26c" + }, + "kdl": { + "revision": "b37e3d58e5c5cf8d739b315d6114e02d42e66664" + }, + "kotlin": { + "revision": "76f53c48d29e8588934fb55b0240d7bdfe00bfe5" + }, + "koto": { + "revision": "cbf637e5163065934c827d254b293f4d2f08f523" + }, + "kusto": { + "revision": "8353a1296607d6ba33db7c7e312226e5fc83e8ce" + }, + "lalrpop": { + "revision": "194c25539f435de415ee0551a5f07058833da915" + }, + "latex": { + "revision": "87e4059f01bed363230dc349f794ce4cc580e862" + }, + "ledger": { + "revision": "a2eff7fee59ee6adfc4a3646e2f41ba3b340a97d" + }, + "leo": { + "revision": "6ca11a96fc2cab51217e0cf4a2f9ed3ea63e28fb" + }, + "linkerscript": { + "revision": "f99011a3554213b654985a4b0a65b3b032ec4621" + }, + "liquid": { + "revision": "23ac814111e2b4b4b083e2c92219af2d5b74d13d" + }, + "liquidsoap": { + "revision": "14feafa91630afb1ab9988cf9b738b7ea29f3f89" + }, + "llvm": { + "revision": "c14cb839003348692158b845db9edda201374548" + }, + "lua": { + "revision": "34e60e7f45fc313463c68090d88d742a55d1bd7a" + }, + "luadoc": { + "revision": "873612aadd3f684dd4e631bdf42ea8990c57634e" + }, + "luap": { + "revision": "c134aaec6acf4fa95fe4aa0dc9aba3eacdbbe55a" + }, + "luau": { + "revision": "fbadc96272f718dba267628ba7b0e694c368cef3" + }, + "m68k": { + "revision": "e128454c2210c0e0c10b68fe45ddb8fee80182a3" + }, + "make": { + "revision": "a4b9187417d6be349ee5fd4b6e77b4172c6827dd" + }, + "markdown": { + "revision": "5cdc549ab8f461aff876c5be9741027189299cec" + }, + "markdown_inline": { + "revision": "5cdc549ab8f461aff876c5be9741027189299cec" + }, + "matlab": { + "revision": "306c43ab28b7b8a4976e40ff0a7c26b019ad52df" + }, + "menhir": { + "revision": "be8866a6bcc2b563ab0de895af69daeffa88fe70" + }, + "mermaid": { + "revision": "90ae195b31933ceb9d079abfa8a3ad0a36fee4cc" + }, + "meson": { + "revision": "c5fffb8edd39f22644084ab3f73a924a75721ee3" + }, + "mlir": { + "revision": "0238b7fb6a630f77b3fc8b8a48285ef6ed45cbcc" + }, + "muttrc": { + "revision": "173b0ab53a9c07962c9777189c4c70e90f1c1837" + }, + "nasm": { + "revision": "570f3d7be01fffc751237f4cfcf52d04e20532d1" + }, + "nginx": { + "revision": "281d184b8240b2b22670b8907b57b6d6842db6f3" + }, + "nickel": { + "revision": "ddaa2bc22355effd97c0d6b09ff5962705c6368d" + }, + "nim": { + "revision": "897e5d346f0b59ed62b517cfb0f1a845ad8f0ab7" + }, + "nim_format_string": { + "revision": "d45f75022d147cda056e98bfba68222c9c8eca3a" + }, + "ninja": { + "revision": "0a95cfdc0745b6ae82f60d3a339b37f19b7b9267" + }, + "nix": { + "revision": "456b14a2fa6315abc7e02fcffaf4a1f35d4955d3" + }, + "norg": { + "revision": "d89d95af13d409f30a6c7676387bde311ec4a2c8" + }, + "nqc": { + "revision": "14e6da1627aaef21d2b2aa0c37d04269766dcc1d" + }, + "objc": { + "revision": "62e61b6f5c0289c376d61a8c91faf6435cde9012" + }, + "objdump": { + "revision": "28d3b2e25a0b1881d1b47ed1924ca276c7003d45" + }, + "ocaml": { + "revision": "5f7a97e9757d8afe6c0b0b5dd8734cf59f35456e" + }, + "ocaml_interface": { + "revision": "5f7a97e9757d8afe6c0b0b5dd8734cf59f35456e" + }, + "ocamllex": { + "revision": "4b9898ccbf198602bb0dec9cd67cc1d2c0a4fad2" + }, + "odin": { + "revision": "3fee7964bbfb2554deef12c224344f3870d15375" + }, + "org": { + "revision": "64cfbc213f5a83da17632c95382a5a0a2f3357c1" + }, + "pascal": { + "revision": "d0ebabefaea9ac3f6fc3004cf08cd121b66da9e4" + }, + "passwd": { + "revision": "20239395eacdc2e0923a7e5683ad3605aee7b716" + }, + "pem": { + "revision": "217ff2af3f2db15a79ab7e3d21ea1e0c17e71a1a" + }, + "perl": { + "revision": "76ab9a52b9dd2a1758aae3da8286519d995037e9" + }, + "php": { + "revision": "2bce5a6588ad6d53ffe5effaf9708682f0fbfc9b" + }, + "php_only": { + "revision": "2bce5a6588ad6d53ffe5effaf9708682f0fbfc9b" + }, + "phpdoc": { + "revision": "fe3202e468bc17332bec8969f2b50ff1f1da3a46" + }, + "pioasm": { + "revision": "afece58efdb30440bddd151ef1347fa8d6f744a9" + }, + "po": { + "revision": "bd860a0f57f697162bf28e576674be9c1500db5e" + }, + "pod": { + "revision": "0bf8387987c21bf2f8ed41d2575a8f22b139687f" + }, + "poe_filter": { + "revision": "592476d81f95d2451f2ca107dc872224c76fecdf" + }, + "pony": { + "revision": "73ff874ae4c9e9b45462673cbc0a1e350e2522a7" + }, + "powershell": { + "revision": "ebe2ab2f642eda2072c68c8de02e83973c26f33c" + }, + "printf": { + "revision": "0e0aceabbf607ea09e03562f5d8a56f048ddea3d" + }, + "prisma": { + "revision": "eca2596a355b1a9952b4f80f8f9caed300a272b5" + }, + "problog": { + "revision": "93c69d2f84d8a167c0a3f4a8d51ccefe365a4dc8" + }, + "prolog": { + "revision": "93c69d2f84d8a167c0a3f4a8d51ccefe365a4dc8" + }, + "promql": { + "revision": "77625d78eebc3ffc44d114a07b2f348dff3061b0" + }, + "properties": { + "revision": "9d09f5f200c356c50c4103d36441309fd61b48d1" + }, + "proto": { + "revision": "e9f6b43f6844bd2189b50a422d4e2094313f6aa3" + }, + "prql": { + "revision": "09e158cd3650581c0af4c49c2e5b10c4834c8646" + }, + "psv": { + "revision": "7eb7297823605392d2bbcc4c09b1cd18d6fa9529" + }, + "pug": { + "revision": "a7ff31a38908df9b9f34828d21d6ca5e12413e18" + }, + "puppet": { + "revision": "584522f32495d648b18a53ccb52d988e60de127d" + }, + "purescript": { + "revision": "daf9b3e2be18b0b2996a1281f7783e0d041d8b80" + }, + "pymanifest": { + "revision": "be062582956165019d3253794b4d712f66dfeaaa" + }, + "python": { + "revision": "7f4b9c2d8039701b0579b7c060a918f8548aa7cd" + }, + "ql": { + "revision": "1d3e2ff34f1113fadc0ff174c8a01cd4227af7fd" + }, + "qmldir": { + "revision": "6b2b5e41734bd6f07ea4c36ac20fb6f14061c841" + }, + "qmljs": { + "revision": "6d4db242185721e1f5ef21fde613ca90c743ec47" + }, + "query": { + "revision": "f767fb0ac5e711b6d44c5e0c8d1f349687a86ce0" + }, + "r": { + "revision": "2097fa502efa21349d26af0ffee55d773015e481" + }, + "racket": { + "revision": "5b211bf93021d1c45f39aa96898be9f794f087e4" + }, + "ralph": { + "revision": "f6d81bf7a4599c77388035439cf5801cd461ff77" + }, + "rasi": { + "revision": "6c9bbcfdf5f0f553d9ebc01750a3aa247a37b8aa" + }, + "rbs": { + "revision": "8d8e65ac3f77fbc9e15b1cdb9f980a3e0ac3ab99" + }, + "re2c": { + "revision": "c18a3c2f4b6665e35b7e50d6048ea3cff770c572" + }, + "readline": { + "revision": "74addc90fc539d31d413c0c7cf7581997a7fa46e" + }, + "regex": { + "revision": "58f4caf9db12db3b38b81c77d274aa73c9e85aca" + }, + "rego": { + "revision": "20b5a5958c837bc9f74b231022a68a594a313f6d" + }, + "requirements": { + "revision": "5ad9b7581b3334f6ad492847d007f2fac6e6e5f2" + }, + "rescript": { + "revision": "4606cd81c4c31d1d02390fee530858323410a74c" + }, + "rnoweb": { + "revision": "1a74dc0ed731ad07db39f063e2c5a6fe528cae7f" + }, + "robot": { + "revision": "322e4cc65754d2b3fdef4f2f8a71e0762e3d13af" + }, + "robots": { + "revision": "8e3a4205b76236bb6dbebdbee5afc262ce38bb62" + }, + "roc": { + "revision": "ef46edd0c03ea30a22f7e92bc68628fb7231dc8a" + }, + "ron": { + "revision": "78938553b93075e638035f624973083451b29055" + }, + "rst": { + "revision": "5120f6e59284cb8b85b450bd2db0bd352635ba9f" + }, + "ruby": { + "revision": "83aec5f7d1659aaa79e6f24b406a9cd49b87e8e8" + }, + "rust": { + "revision": "2ace7a922a755960f44d73a7bb1efffeb4cc5501" + }, + "scala": { + "revision": "a9af6356f8e31f04e870587bca79bc2b15808ff5" + }, + "scfg": { + "revision": "a5512800ea0220da4abbae61b8aea8423d1549aa" + }, + "scheme": { + "revision": "63e25a4a84142ae7ee0ee01fe3a32c985ca16745" + }, + "scss": { + "revision": "c478c6868648eff49eb04a4df90d703dc45b312a" + }, + "sflog": { + "revision": "46d4a12e4e90b10a575b7b16ea3b6ead50322074" + }, + "slang": { + "revision": "3ed23c04a412a0559162d9cadf96dfff7cb36079" + }, + "slint": { + "revision": "4e2765d4cac1f03ada6f635eeb6008d1d0aff5a3" + }, + "smali": { + "revision": "fdfa6a1febc43c7467aa7e937b87b607956f2346" + }, + "smithy": { + "revision": "fa898ac0885d1da9a253695c3e0e91f5efc587cd" + }, + "snakemake": { + "revision": "e909815acdbe37e69440261ebb1091ed52e1dec6" + }, + "solidity": { + "revision": "ee5a2d2ba30b487c4bbf613d2ef310a454c09c7c" + }, + "soql": { + "revision": "46d4a12e4e90b10a575b7b16ea3b6ead50322074" + }, + "sosl": { + "revision": "46d4a12e4e90b10a575b7b16ea3b6ead50322074" + }, + "sourcepawn": { + "revision": "6b9bf9cbab91443380d2ca8a2f6c491cc7fac5bf" + }, + "sparql": { + "revision": "d853661ca680d8ff7f8d800182d5782b61d0dd58" + }, + "sql": { + "revision": "f551a8fa69dc9aea479b93fae34c3ea7be15f931" + }, + "squirrel": { + "revision": "072c969749e66f000dba35a33c387650e203e96e" + }, + "ssh_config": { + "revision": "77450e8bce8853921512348f83c73c168c71fdfb" + }, + "starlark": { + "revision": "018d0e09d9d0f0dd6740a37682b8ee4512e8b2ac" + }, + "strace": { + "revision": "d819cdd5dbe455bd3c859193633c8d91c0df7c36" + }, + "styled": { + "revision": "764af55fc6b8e5ae177eb272f5c5de6238db23e6" + }, + "supercollider": { + "revision": "1a8ee0da9a4f2df5a8a22f4d637ac863623a78a7" + }, + "superhtml": { + "revision": "3325bbb2dda260131a8db0cae1f1f557d17ebced" + }, + "surface": { + "revision": "f4586b35ac8548667a9aaa4eae44456c1f43d032" + }, + "svelte": { + "revision": "ae5199db47757f785e43a14b332118a5474de1a2" + }, + "swift": { + "revision": "d351cb321c28f0a3e66242ef2f61b1f890ec4b44" + }, + "sxhkdrc": { + "revision": "440d5f913d9465c9c776a1bd92334d32febcf065" + }, + "systemtap": { + "revision": "f2b378a9af0b7e1192cff67a5fb45508c927205d" + }, + "t32": { + "revision": "0f6a5b1e031c97ebf58d3c76eadb2c6bf1e4f780" + }, + "tablegen": { + "revision": "b1170880c61355aaf38fc06f4af7d3c55abdabc4" + }, + "tact": { + "revision": "83e264928fa194b7283428527259e88e54205264" + }, + "tcl": { + "revision": "cdba4ab96a9896492d0d5219b70300c8783ca4e7" + }, + "teal": { + "revision": "485fbdc00d811b01b2090dff4d0469fd1d0350f5" + }, + "templ": { + "revision": "4519e3ec9ca92754ca25659bb1fd410d5e0f8d88" + }, + "terraform": { + "revision": "9e3ec9848f28d26845ba300fd73c740459b83e9b" + }, + "textproto": { + "revision": "568471b80fd8793d37ed01865d8c2208a9fefd1b" + }, + "thrift": { + "revision": "68fd0d80943a828d9e6f49c58a74be1e9ca142cf" + }, + "tiger": { + "revision": "a7f11d946b44244f71df41d2a78af0665d618dae" + }, + "tlaplus": { + "revision": "8a8413f1d08e7ee40b347206d26eac4324db9fd9" + }, + "tmux": { + "revision": "0252ecd080016e45e6305ef1a943388f5ae2f4b4" + }, + "todotxt": { + "revision": "3937c5cd105ec4127448651a21aef45f52d19609" + }, + "toml": { + "revision": "16a30c83ce427385b8d14939c45c137fcfca6c42" + }, + "tsv": { + "revision": "7eb7297823605392d2bbcc4c09b1cd18d6fa9529" + }, + "tsx": { + "revision": "73c4447796b251295b498227bad028d88dc1918b" + }, + "turtle": { + "revision": "7f789ea7ef765080f71a298fc96b7c957fa24422" + }, + "twig": { + "revision": "085648e01d1422163a1702a44e72303b4e2a0bd1" + }, + "typescript": { + "revision": "73c4447796b251295b498227bad028d88dc1918b" + }, + "typespec": { + "revision": "0ee05546d73d8eb64635ed8125de6f35c77759fe" + }, + "typoscript": { + "revision": "43b221c0b76e77244efdaa9963e402a17c930fbc" + }, + "typst": { + "revision": "8b8b16ef1b40cbecbe3f754b1c1c966b5a0904fe" + }, + "udev": { + "revision": "8f58696e79092b4ad6bf197415bbd0970acf15cd" + }, + "ungrammar": { + "revision": "debd26fed283d80456ebafa33a06957b0c52e451" + }, + "unison": { + "revision": "bc06e1eb100e1c0fab9bd89a9ca55d646ac80fc4" + }, + "usd": { + "revision": "4e0875f724d94d0c2ff36f9b8cb0b12f8b20d216" + }, + "uxntal": { + "revision": "ad9b638b914095320de85d59c49ab271603af048" + }, + "v": { + "revision": "ea538758a1273b59774dc9179cde460d9c73fd89" + }, + "vala": { + "revision": "8f690bfa639f2b83d1fb938ed3dd98a7ba453e8b" + }, + "vento": { + "revision": "3321077d7446c1b3b017c294fd56ce028ed817fe" + }, + "verilog": { + "revision": "0dacb911daa9614a7c7e79a594d4cb9f478e6554" + }, + "vhdl": { + "revision": "d6e8301999336b47d663052d43f983c3edeb01dd" + }, + "vhs": { + "revision": "09f8fbfe40a3a699b200daca7d92e65fbbe9f9e6" + }, + "vim": { + "revision": "f3cd62d8bd043ef20507e84bb6b4b53731ccf3a7" + }, + "vimdoc": { + "revision": "59c539286e7487b267bc7808b16833f9e3ad6793" + }, + "vrl": { + "revision": "274b3ce63f72aa8ffea18e7fc280d3062d28f0ba" + }, + "vue": { + "revision": "22bdfa6c9fc0f5ffa44c6e938ec46869ac8a99ff" + }, + "wgsl": { + "revision": "40259f3c77ea856841a4e0c4c807705f3e4a2b65" + }, + "wgsl_bevy": { + "revision": "47c1818d245a6156a488c4c4d06e9336714bae9b" + }, + "wing": { + "revision": "76e0c25844a66ebc6e866d690fcc5f4e90698947" + }, + "wit": { + "revision": "81490b4e74c792369e005f72b0d46fe082d3fed2" + }, + "xcompose": { + "revision": "fff3e72242aa110ebba6441946ea4d12d200fa68" + }, + "xml": { + "revision": "cd1316e476ec40da6ce1fb5749c9d7e6b4f1090c" + }, + "xresources": { + "revision": "630af80f563ede09a652a808277950c36306e3a3" + }, + "yaml": { + "revision": "7b03feefd36b5f155465ca736c6304aca983b267" + }, + "yang": { + "revision": "2c0e6be8dd4dcb961c345fa35c309ad4f5bd3502" + }, + "yuck": { + "revision": "e877f6ade4b77d5ef8787075141053631ba12318" + }, + "zathurarc": { + "revision": "0554b4a5d313244b7fc000cbb41c04afae4f4e31" + }, + "zig": { + "revision": "eb7d58c2dc4fbeea4745019dee8df013034ae66b" + }, + "ziggy": { + "revision": "42b6f5d7320340bc5903c4c29d34065e8517a549" + }, + "ziggy_schema": { + "revision": "42b6f5d7320340bc5903c4c29d34065e8517a549" + } +} 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..7733202ed --- /dev/null +++ b/lua/nvim-treesitter/caching.lua @@ -0,0 +1,71 @@ +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 = {} + + ---@type table> + local items = setmetatable({}, { + __index = function(tbl, key) + rawset(tbl, key, {}) + return rawget(tbl, key) + end, + }) + + ---@type table + local loaded_buffers = {} + + ---@param type_name string + ---@param bufnr integer + ---@param value any + function cache.set(type_name, bufnr, value) + if not loaded_buffers[bufnr] then + loaded_buffers[bufnr] = true + -- Clean up the cache if the buffer is detached + -- to avoid memory leaks + api.nvim_buf_attach(bufnr, false, { + on_detach = function() + cache.clear_buffer(bufnr) + loaded_buffers[bufnr] = nil + return true + end, + on_reload = function() end, -- this is needed to prevent on_detach being called on buffer reload + }) + end + + items[bufnr][type_name] = value + end + + ---@param type_name string + ---@param bufnr integer + ---@return any + function cache.get(type_name, bufnr) + return items[bufnr][type_name] + end + + ---@param type_name string + ---@param bufnr integer + ---@return boolean + function cache.has(type_name, bufnr) + return cache.get(type_name, bufnr) ~= nil + end + + ---@param type_name string + ---@param bufnr integer + function cache.remove(type_name, bufnr) + items[bufnr][type_name] = nil + end + + ---@param bufnr integer + function cache.clear_buffer(bufnr) + items[bufnr] = nil + end + + return cache +end + +return M diff --git a/lua/nvim-treesitter/compat.lua b/lua/nvim-treesitter/compat.lua new file mode 100644 index 000000000..0ad010030 --- /dev/null +++ b/lua/nvim-treesitter/compat.lua @@ -0,0 +1,39 @@ +-- Shim module to address deprecations across nvim versions +local ts = vim.treesitter +local tsq = ts.query + +local M = {} + +function M.get_query_files(lang, query_group, is_included) + return (tsq.get_files or tsq.get_query_files)(lang, query_group, is_included) +end + +function M.get_query(lang, query_name) + return (tsq.get or tsq.get_query)(lang, query_name) +end + +function M.parse_query(lang, query) + return (tsq.parse or tsq.parse_query)(lang, query) +end + +function M.get_range(node, source, metadata) + return (ts.get_range or tsq.get_range)(node, source, metadata) +end + +function M.get_node_text(node, bufnr) + return (ts.get_node_text or tsq.get_node_text)(node, bufnr) +end + +function M.require_language(lang, opts) + return (ts.language.add or ts.language.require_language)(lang, opts) +end + +function M.flatten(t) + if vim.fn.has "nvim-0.11" == 1 then + return vim.iter(t):flatten():totable() + else + return vim.tbl_flatten(t) + end +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..a3ec30fb2 --- /dev/null +++ b/lua/nvim-treesitter/configs.lua @@ -0,0 +1,616 @@ +local api = vim.api + +local queries = require "nvim-treesitter.query" +local ts = require "nvim-treesitter.compat" +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 parser_install_dir string|nil + +---@type TSConfig +local config = { + modules = {}, + sync_install = false, + ensure_installed = {}, + auto_install = false, + ignore_install = {}, + parser_install_dir = nil, +} + +-- List of modules that need to be setup on initialization. +---@type TSModule[][] +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 keymaps table +---@field is_supported function(string): boolean +---@field attach function(string) +---@field detach function(string) +---@field enabled_buffers table +---@field additional_vim_regex_highlighting boolean|string[] + +---@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", -- set to `false` to disable one of the mappings + 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}|nil 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.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 buffer +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 buffer +---@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 buffer +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 buffer +---@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}|nil table to find modules +---@return string[] modules list of module paths +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|nil 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 = config.parser_install_dir or utils.get_package_path() + 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_ignored_parser_installs() + return config.ignore_install or {} +end + +function M.get_ensure_installed_parsers() + if type(config.ensure_installed) == "string" then + return { config.ensure_installed } + end + 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..759599876 --- /dev/null +++ b/lua/nvim-treesitter/fold.lua @@ -0,0 +1,123 @@ +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 + + ---@type table + local start_counts = {} + ---@type table + 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 ---@type integer, integer, integer + if match.metadata and match.metadata.range then + start, _, stop, stop_col = unpack(match.metadata.range) ---@type integer, integer, integer, integer + else + start, _, stop, stop_col = match.node:range() ---@type integer, integer, integer, integer + 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 + + ---@type string[] + 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..be265f7d0 100644 --- a/lua/nvim-treesitter/health.lua +++ b/lua/nvim-treesitter/health.lua @@ -1,174 +1,176 @@ -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 ts = require "nvim-treesitter.compat" + +local health = vim.health or require "health" + +-- "report_" prefix has been deprecated, use the recommended replacements if they exist. +local _start = health.start or health.report_start +local _ok = health.ok or health.report_ok +local _warn = health.warn or health.report_warn +local _error = health.error or health.report_error 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') + _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.9.2" ~= 1 then + _error "Nvim-treesitter requires Nvim 0.9.2 or newer" + end + if fn.executable "tree-sitter" == 0 then + _warn( + "`tree-sitter` executable not found (parser generator, only needed for :TSInstallFromGrammar," + .. " not required for :TSInstall)" + ) + else + _ok( + "`tree-sitter` found " + .. (utils.ts_cli_version() or "(unknown version)") + .. " (parser generator, only needed for :TSInstallFromGrammar)" + ) + end + + if fn.executable "node" == 0 then + _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] + _ok("`node` found " .. version .. " (only needed for :TSInstallFromGrammar)") + end + + if fn.executable "git" == 0 then + _error("`git` executable not found.", { + "Install it with your package manager.", + "Check that your `$PATH` is set correctly.", + }) + else + _ok "`git` executable found." + end + + local cc = shell.select_executable(install.compilers) + if not cc then + _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] + _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 ' + _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 ' + _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 + _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" .. string.rep(" ", 9) .. "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(" ", 20 - (#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 + _start(table.concat(parser_installation, "\n")) if #error_collection > 0 then - health.start('The following errors have been detected in query files:') + _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 = ts.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(ts.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, '')) + _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..5a3cc2e86 --- /dev/null +++ b/lua/nvim-treesitter/highlight.lua @@ -0,0 +1,49 @@ +local configs = require "nvim-treesitter.configs" + +local M = {} + +---@param config TSModule +---@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" + + ---@diagnostic disable-next-line: param-type-mismatch + return additional_hl and (not is_table or vim.tbl_contains(additional_hl, lang)) +end + +---@param bufnr integer +---@param lang string +function M.attach(bufnr, lang) + local config = configs.get_module "highlight" + vim.treesitter.start(bufnr, lang) + if config and should_enable_vim_regex(config, lang) then + vim.bo[bufnr].syntax = "ON" + end +end + +---@param bufnr integer +function M.detach(bufnr) + vim.treesitter.stop(bufnr) +end + +---@deprecated +function M.start(...) + vim.notify( + "`nvim-treesitter.highlight.start` is deprecated: use `nvim-treesitter.highlight.attach` or `vim.treesitter.start`", + vim.log.levels.WARN + ) + M.attach(...) +end + +---@deprecated +function M.stop(...) + vim.notify( + "`nvim-treesitter.highlight.stop` is deprecated: use `nvim-treesitter.highlight.detach` or `vim.treesitter.stop`", + vim.log.levels.WARN + ) + M.detach(...) +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..78f0915c8 --- /dev/null +++ b/lua/nvim-treesitter/incremental_selection.lua @@ -0,0 +1,167 @@ +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 utils = require "nvim-treesitter.utils" + +local M = {} + +---@type table> +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 starts with 1 and the ending is inclusive. +---@return integer, integer, integer, integer +local function visual_selection_range() + local _, csrow, cscol, _ = unpack(vim.fn.getpos "v") ---@type integer, integer, integer, integer + local _, cerow, cecol, _ = unpack(vim.fn.getpos ".") ---@type integer, integer, integer, integer + + local start_row, start_col, end_row, end_col ---@type integer, integer, integer, integer + + 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 + +---@param node TSNode +---@return boolean +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 + +---@param get_parent fun(node: TSNode): TSNode|nil +---@return fun():nil +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] ---@type TSNode + 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] ---@type TSNode + 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", +} + +---@param bufnr integer +function M.attach(bufnr) + local config = configs.get_module "incremental_selection" + for funcname, mapping in pairs(config.keymaps) do + if mapping then + local mode = funcname == "init_selection" and "n" or "x" + local rhs = M[funcname] ---@type function + + if not rhs then + utils.notify("Unknown keybinding: " .. funcname .. debug.traceback(), vim.log.levels.ERROR) + else + vim.keymap.set(mode, mapping, rhs, { buffer = bufnr, silent = true, desc = FUNCTION_DESCRIPTIONS[funcname] }) + end + end + end +end + +function M.detach(bufnr) + local config = configs.get_module "incremental_selection" + for f, mapping in pairs(config.keymaps) do + if mapping then + local mode = f == "init_selection" and "n" or "x" + local ok, err = pcall(vim.keymap.del, mode, mapping, { buffer = bufnr }) + if not ok then + utils.notify(string.format('%s "%s" for mode %s', err, mapping, mode), vim.log.levels.ERROR) + end + end + end +end + +return M diff --git a/lua/nvim-treesitter/indent.lua b/lua/nvim-treesitter/indent.lua index ee513c351..19e7ef1ee 100644 --- a/lua/nvim-treesitter/indent.lua +++ b/lua/nvim-treesitter/indent.lua @@ -1,30 +1,33 @@ local ts = vim.treesitter +local parsers = require "nvim-treesitter.parsers" 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 '' + return vim.api.nvim_buf_get_lines(0, lnum - 1, lnum, false)[1] or "" end ---@param lnum integer ---@return integer local function get_indentcols_at_line(lnum) - local _, indentcols = getline(lnum):find('^%s*') + local _, indentcols = getline(lnum):find "^%s*" return indentcols or 0 end ---@param root TSNode ---@param lnum integer ---@param col? integer ----@return TSNode? +---@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) @@ -33,17 +36,25 @@ end ---@param root TSNode ---@param lnum integer ---@param col? integer ----@return TSNode? +---@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 node TSNode +---@return number +local function node_length(node) + local _, _, start_byte = node:start() + local _, _, end_byte = node:end_() + return end_byte - start_byte +end + ---@param bufnr integer ---@param node TSNode ---@param delimiter string ----@return TSNode? child ----@return boolean? is_end +---@return TSNode|nil child +---@return boolean|nil is_end local function find_delimiter(bufnr, node, delimiter) for child, _ in node:iter_children() do if child:type() == delimiter then @@ -51,9 +62,8 @@ local function find_delimiter(bufnr, node, delimiter) 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 .. ']*', '') + local escaped_delimiter = delimiter:gsub("[%-%.%+%[%]%(%)%$%^%%%?%*]", "%%%1") + trimmed_after_delim, _ = line:sub(end_char[2] + 1):gsub("[%s" .. escaped_delimiter .. "]*", "") return child, #trimmed_after_delim == 0 end end @@ -65,7 +75,7 @@ end ---@param hash_fn fun(...): any ---@return F local function memoize(fn, hash_fn) - local cache = setmetatable({}, { __mode = 'kv' }) ---@type table + local cache = setmetatable({}, { __mode = "kv" }) ---@type table return function(...) local key = hash_fn(...) @@ -80,53 +90,59 @@ local function memoize(fn, hash_fn) end local get_indents = memoize(function(bufnr, root, lang) - ---@type table> local map = { - ['indent.auto'] = {}, - ['indent.begin'] = {}, - ['indent.end'] = {}, - ['indent.dedent'] = {}, - ['indent.branch'] = {}, - ['indent.ignore'] = {}, - ['indent.align'] = {}, - ['indent.zero'] = {}, + ["indent.auto"] = {}, + ["indent.begin"] = {}, + ["indent.end"] = {}, + ["indent.dedent"] = {}, + ["indent.branch"] = {}, + ["indent.ignore"] = {}, + ["indent.align"] = {}, + ["indent.zero"] = {}, } - local query = ts.query.get(lang, 'indents') + --TODO(clason): remove when dropping Nvim 0.8 compat + local query = (ts.query.get or ts.get_query)(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 + if query.captures[id]:sub(1, 1) ~= "_" then map[query.captures[id]][node:id()] = metadata or {} end end return map end, function(bufnr, root, lang) - return tostring(bufnr) .. root:id() .. '_' .. 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$') }) + --TODO(clason): replace when dropping Nvim 0.8 compat + 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 { vim.fn.line "w0" - 1, vim.fn.line "w$" } + 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 ---@type TSNode, LanguageTree 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 not root or node_length(root) >= node_length(local_root) then root = local_root lang_tree = tree end @@ -139,19 +155,20 @@ 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(getline(lnum), "^%s*$") ~= nil + local node ---@type TSNode + 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 + if 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 + if 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 @@ -159,7 +176,7 @@ function M.get_indent(lnum) node = get_last_node_at_line(root, prevlnum, col) end end - if node and q['indent.end'][node:id()] then + if q["indent.end"][node:id()] then node = get_first_node_at_line(root, lnum) end else @@ -175,18 +192,18 @@ 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["indent.zero"][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()] + 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 @@ -197,8 +214,8 @@ function M.get_indent(lnum) -- 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()] + not q["indent.begin"][node:id()] + and q["indent.ignore"][node:id()] and node:start() < lnum - 1 and lnum - 1 <= node:end_() then @@ -211,10 +228,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["indent.branch"][node:id()] and srow == lnum - 1) or (q["indent.dedent"][node:id()] and srow ~= lnum - 1)) then indent = indent - indent_size is_processed = true @@ -225,21 +239,21 @@ 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.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"]) ) then indent = indent + indent_size is_processed = true end - if is_in_err and not q['indent.align'][node:id()] then + 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")) @@ -247,41 +261,34 @@ function M.get_indent(lnum) -- (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()] + 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? + 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|nil, boolean|nil + local c_delim_node, c_is_last_in_line ---@type TSNode|nil, boolean|nil, boolean|nil 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 metadata["indent.open_delimiter"] then + o_delim_node, o_is_last_in_line = find_delimiter(bufnr, node, metadata["indent.open_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']) + 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? + local c_srow = nil if c_delim_node then - c_srow = c_delim_node:start() + c_srow, _ = c_delim_node:start() end if o_is_last_in_line then -- hanging indent (previous line ended with starting delimiter) @@ -303,7 +310,7 @@ function M.get_indent(lnum) -- 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 = o_scol + (metadata["indent.increment"] or 1) indent_is_absolute = true end end @@ -314,7 +321,7 @@ function M.get_indent(lnum) -- 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 + 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 @@ -343,4 +350,17 @@ function M.get_indent(lnum) return indent end +---@type table +local indent_funcs = {} + +---@param bufnr integer +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..6e94b357d --- /dev/null +++ b/lua/nvim-treesitter/info.lua @@ -0,0 +1,190 @@ +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'}} +---@param modulelist string[] +---@return table +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 + +---@param list string[] +---@return integer length +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 + +---@param curbuf integer +---@param origbuf integer +---@param parserlist string[] +---@param namespace string +---@param modulelist string[] +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 + + ---@type string[] + 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 + +---@return string[] +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..cd12dbb81 100644 --- a/lua/nvim-treesitter/install.lua +++ b/lua/nvim-treesitter/install.lua @@ -1,649 +1,781 @@ +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 compat = require "nvim-treesitter.compat" local M = {} ---- ---- PARSER INFO ---- +---@class LockfileInfo +---@field revision string ----@param lang string ----@return InstallInfo? -local function get_parser_install_info(lang) - local parser_config = parsers[lang] +---@type table +local lockfile = {} - if not parser_config then - log.error('Parser not available for language "' .. lang .. '"') +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 + +local started_commands = 0 +local finished_commands = 0 +local failed_commands = 0 +local complete_std_output = {} +local complete_error_output = {} + +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? +---@return function +local function reattach_if_possible_fn(lang, error_on_fail) + return function() + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if parsers.get_buf_lang(buf) == lang then + vim._ts_remove_language(lang) + local ok, err + if vim.treesitter.language.add then + local ft = vim.bo[buf].filetype + ok, err = pcall(vim.treesitter.language.add, lang, { filetype = ft }) + else + ok, err = pcall(compat.require_language, lang) + end + if not ok and error_on_fail then + vim.notify("Could not load parser for " .. lang .. ": " .. vim.inspect(err)) + end + for _, mod in ipairs(require("nvim-treesitter.configs").available_modules()) do + if ok then + require("nvim-treesitter.configs").reattach_module(mod, buf, lang) + else + require("nvim-treesitter.configs").detach_module(mod, buf) + end + end + end + end + end +end + +---@param lang 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 + +---@param lang string +---@return string|nil +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 + + if lockfile[lang] then + return lockfile[lang].revision + end +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 + +-- Clean path for use in a prefix comparison +---@param input string +---@return string +local function clean_path(input) + local pth = vim.fn.fnamemodify(input, ":p") + if fn.has "win32" == 1 then + pth = pth:gsub("/", "\\") + end + return pth +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 = clean_path(install_dir) + for _, path in ipairs(matched_parsers) do + local abspath = clean_path(path) + 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 string[] +local function outdated_parsers() + return vim.tbl_filter(function(lang) ---@param lang string + 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 + 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 ---- 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' }) +---@param cmd Command +---@return string command +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 + + local command = string.format("%s %s", cmd.cmd, options) + if cmd.opts and cmd.opts.cwd then + command = shell.make_directory_change_for_command(cmd.opts.cwd, command) + end + return command +end + +---@param cmd_list Command[] +---@return boolean +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 + + 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 + + ---@type string compile_location only needed for typescript installs. + local compile_location + if from_local_path then + compile_location = repo.url + if repo.location then + compile_location = utils.join_path(compile_location, repo.location) + end + 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", "--no-bindings", "--abi", vim.treesitter.language_version } + else + M.ts_generate_args = { "generate", "--no-bindings" } + 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) ---@param c string + return type(c) == "string" + end, M.compilers), + '", "' + ) .. '" are not executable.') + return + end + + local revision = repo.revision + if not revision then + revision = get_revision(lang) + end + + ---@class Command + ---@field cmd string + ---@field info string + ---@field err string + ---@field opts CmdOpts + + ---@class CmdOpts + ---@field args string[] + ---@field cwd string + + ---@type Command[] + 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() or "", lang .. ".revision")) + end, + }, + { -- auto-attach modules after installation + cmd = reattach_if_possible_fn(lang, true), + }, + }) + 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|string +---@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 ---@class InstallOptions ----@field force? boolean ----@field generate? boolean ----@field max_jobs? integer ----@field summary? boolean +---@field with_sync boolean +---@field ask_reinstall boolean|string +---@field generate_from_grammar boolean +---@field exclude_configured_parsers boolean ---- Install a parser ----@async ----@param languages string[] +-- Install a parser ---@param options? InstallOptions ----@return boolean true if installation successful -local function install(languages, options) +---@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 - local cache_dir = fs.normalize(fn.stdpath('cache') --[[@as string]]) - if not uv.fs_stat(cache_dir) then - fn.mkdir(cache_dir, 'p') - end + 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 install_dir = config.get_install_dir('parser') + local cache_folder, err = utils.get_cache_dir() + if err then + return api.nvim_err_writeln(err) + end + assert(cache_folder) - 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 + local install_folder + install_folder, err = configs.get_parser_install_dir() + if err then + return api.nvim_err_writeln(err) + end + install_folder = install_folder and clean_path(install_folder) + assert(install_folder) - 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) + local languages ---@type string[] + local ask ---@type boolean|string + if ... == "all" then + languages = parsers.available_parsers() + ask = false + else + languages = compat.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 - 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) +function M.setup_auto_install() + local function try_install_curr_lang() + 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 - 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 + try_install_curr_lang() - logger:info('Language uninstalled') + vim.api.nvim_create_autocmd("FileType", { + pattern = { "*" }, + group = vim.api.nvim_create_augroup("NvimTreesitter-auto_install", { clear = true }), + callback = try_install_curr_lang, + }) 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 +function M.update(options) + options = options or {} + return function(...) + M.lockfile = {} + reset_progress_counter() + if ... and ... ~= "all" then + ---@type string[] + local languages = compat.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) + end + if installed == 0 then + utils.notify "Parsers are up-to-date!" + end + else + local parsers_to_update = 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() + M.uninstall(installed) + 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()) + + ---@type string[] + local languages = compat.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 + install_dir = install_dir and clean_path(install_dir) + + 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):" + .. table.concat(all_parsers_after_deletion, ", "), + vim.log.levels.ERROR + ) + end + end, + }, + { -- auto-reattach or detach modules after uninstallation + cmd = reattach_if_possible_fn(lang, false), + }, + } + 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 = {} ---@type Parser[] + -- 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 + + ---@param a Parser + ---@param b Parser + 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 ---@type string + 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 - join(MAX_JOBS, tasks) - if #tasks > 1 then - a.schedule() - if options and options.summary then - log.info('Uninstalled %d/%d languages', done, #tasks) - end + if verbose then + print(vim.inspect(lockfile)) end -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..fed835bbd --- /dev/null +++ b/lua/nvim-treesitter/locals.lua @@ -0,0 +1,365 @@ +-- 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 = vim.treesitter +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 + +---@param bufnr integer +---@return any +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 TSNode: the scope node of the definition +---@param node_text string: the node text to use +---@return string: 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["local"]["definition"] then + table.insert(defs, loc["local"]["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["local"]["scope"] and loc["local"]["scope"].node then + table.insert(scopes, loc["local"]["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["local"]["reference"] and loc["local"]["reference"].node then + table.insert(refs, loc["local"]["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) +---@param node TSNode +---@param bufnr integer +---@return TSNode[] +function M.get_scope_tree(node, bufnr) + local scopes = {} ---@type TSNode[] + + 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 +---@param node TSNode +---@param bufnr integer +---@return fun(): TSNode|nil +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 any: the local list result +---@return table: 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 local_def any The locals result +---@param accumulator function The accumulator function +---@param full_match? string The full match path to append to +---@param last_match? string 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 integer: the buffer +---@return table result: 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.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 TSNode: the definition node +---@param bufnr integer: the buffer +---@param scope_type string: the scope type +function M.get_definition_scopes(node, bufnr, scope_type) + local scopes = {} + local scope_count = 1 ---@type integer|nil + + -- 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 + +---@param node TSNode +---@param bufnr integer +---@return TSNode node +---@return TSNode scope +---@return string|nil kind +function M.find_definition(node, bufnr) + local def_lookup = M.get_definitions_lookup_table(bufnr) + local node_text = ts.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 TSNode the node to find usages for +---@param scope_node TSNode the node to look within +---@return TSNode[]: a list of nodes +function M.find_usages(node, scope_node, bufnr) + bufnr = bufnr or api.nvim_get_current_buf() + local node_text = ts.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 + match = match["local"] + if match.reference and match.reference.node and ts.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 + +---@param node TSNode +---@param bufnr? integer +---@param allow_scope? boolean +---@return TSNode|nil +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 ---@type integer + local col = cursor_pos.col ---@type integer + 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 + +---@param node TSNode +---@return TSNode|nil +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..f6731303d 100644 --- a/lua/nvim-treesitter/parsers.lua +++ b/lua/nvim-treesitter/parsers.lua @@ -1,2703 +1,2693 @@ ----@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 + +for ft, lang in pairs { + automake = "make", + javascriptreact = "javascript", + ecma = "javascript", + jsx = "javascript", + gyp = "python", + html_tags = "html", + ["typescript.tsx"] = "tsx", + ["terraform-vars"] = "terraform", + ["html.handlebars"] = "glimmer", + systemverilog = "verilog", + dosini = "ini", + confini = "ini", + svg = "xml", + xsd = "xml", + xslt = "xml", + expect = "tcl", + mysql = "sql", + sbt = "scala", + neomuttrc = "muttrc", + --- short-hand list from https://github.com/helix-editor/helix/blob/master/languages.toml + rs = "rust", + ex = "elixir", + js = "javascript", + ts = "typescript", + ["c-sharp"] = "csharp", + hs = "haskell", + py = "python", + erl = "erlang", + typ = "typst", + pl = "perl", + uxn = "uxntal", +} do + ts.language.register(lang, ft) +end + +---@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 +---@field use_makefile boolean|nil +---@field cxx_standard string|nil + +---@class ParserInfo +---@field install_info InstallInfo +---@field filetype string +---@field maintainers string[] +---@field experimental boolean|nil +---@field readme_name string|nil + +---@type ParserInfo[] +local list = setmetatable({}, { + __newindex = function(table, parsername, parserconfig) + rawset(table, parsername, parserconfig) + if parserconfig.filetype or vim.fn.has "nvim-0.11" == 0 then + ts.language.register(parsername, parserconfig.filetype or parsername) + end + end, +}) + +list.ada = { + install_info = { + url = "https://github.com/briot/tree-sitter-ada", + files = { "src/parser.c" }, + }, + maintainers = { "@briot" }, +} + +list.agda = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-agda", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@Decodetalkers" }, +} + +list.angular = { + install_info = { + url = "https://github.com/dlvandenberg/tree-sitter-angular", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + filetype = "htmlangular", + maintainers = { "@dlvandenberg" }, + experimental = true, +} + +list.apex = { + install_info = { + url = "https://github.com/aheber/tree-sitter-sfapex", + files = { "src/parser.c" }, + location = "apex", + }, + maintainers = { "@aheber", "@xixiaofinland" }, +} + +list.arduino = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-arduino", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.asm = { + install_info = { + url = "https://github.com/RubixDev/tree-sitter-asm", + files = { "src/parser.c" }, + }, + maintainers = { "@RubixDev" }, +} + +list.astro = { + install_info = { + url = "https://github.com/virchau13/tree-sitter-astro", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@virchau13" }, +} + +list.authzed = { + install_info = { + url = "https://github.com/mleonidas/tree-sitter-authzed", + files = { "src/parser.c" }, + }, + maintainers = { "@mattpolzin" }, +} + +list.awk = { + install_info = { + url = "https://github.com/Beaglefoot/tree-sitter-awk", + files = { "src/parser.c", "src/scanner.c" }, }, } + +list.bash = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-bash", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "sh", + maintainers = { "@TravonteD" }, +} + +list.bass = { + install_info = { + url = "https://github.com/vito/tree-sitter-bass", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.beancount = { + install_info = { + url = "https://github.com/polarmutex/tree-sitter-beancount", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@polarmutex" }, +} + +list.bibtex = { + install_info = { + url = "https://github.com/latex-lsp/tree-sitter-bibtex", + files = { "src/parser.c" }, + }, + filetype = "bib", + maintainers = { "@theHamsta", "@clason" }, +} + +list.bicep = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-bicep", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.bitbake = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-bitbake", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.blueprint = { + install_info = { + url = "https://gitlab.com/gabmus/tree-sitter-blueprint.git", + files = { "src/parser.c" }, + }, + maintainers = { "@gabmus" }, + experimental = true, +} + +list.bp = { + install_info = { + url = "https://github.com/ambroisie/tree-sitter-bp", + files = { "src/parser.c" }, + }, + maintainers = { "@ambroisie" }, +} + +list.c = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-c", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +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 = { "@amaanq" }, +} + +list.cairo = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-cairo", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.capnp = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-capnp", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.chatito = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-chatito", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.clojure = { + install_info = { + url = "https://github.com/sogaiu/tree-sitter-clojure", + files = { "src/parser.c" }, + }, + maintainers = { "@NoahTheDuke" }, +} + +list.cmake = { + install_info = { + url = "https://github.com/uyha/tree-sitter-cmake", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@uyha" }, +} + +list.comment = { + install_info = { + url = "https://github.com/stsewd/tree-sitter-comment", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@stsewd" }, +} + +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.cooklang = { + install_info = { + url = "https://github.com/addcninblue/tree-sitter-cooklang", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@addcninblue" }, +} + +list.corn = { + install_info = { + url = "https://github.com/jakestanger/tree-sitter-corn", + files = { "src/parser.c" }, + }, + maintainers = { "@jakestanger" }, +} + +list.cpon = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-cpon", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.cpp = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-cpp", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + maintainers = { "@theHamsta" }, +} + +list.css = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-css", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@TravonteD" }, +} + +list.csv = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-csv", + files = { "src/parser.c" }, + location = "csv", + }, + maintainers = { "@amaanq" }, +} + +list.cuda = { + install_info = { + url = "https://github.com/theHamsta/tree-sitter-cuda", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + maintainers = { "@theHamsta" }, +} + +list.cue = { + install_info = { + url = "https://github.com/eonpatapon/tree-sitter-cue", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.d = { + install_info = { + url = "https://github.com/gdamore/tree-sitter-d", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.dart = { + install_info = { + url = "https://github.com/UserNobody14/tree-sitter-dart", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@akinsho" }, +} + +list.devicetree = { + install_info = { + url = "https://github.com/joelspadin/tree-sitter-devicetree", + files = { "src/parser.c" }, + }, + filetype = "dts", + maintainers = { "@jedrzejboczar" }, +} + +list.dhall = { + install_info = { + url = "https://github.com/jbellerb/tree-sitter-dhall", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.diff = { + install_info = { + url = "https://github.com/the-mikedavis/tree-sitter-diff", + files = { "src/parser.c" }, + }, + filetype = "gitdiff", + maintainers = { "@gbprod" }, +} + +list.disassembly = { + install_info = { + url = "https://github.com/ColinKennedy/tree-sitter-disassembly", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@ColinKennedy" }, +} + +list.djot = { + install_info = { + url = "https://github.com/treeman/tree-sitter-djot", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@NoahTheDuke" }, +} + +list.dockerfile = { + install_info = { + url = "https://github.com/camdencheek/tree-sitter-dockerfile", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@camdencheek" }, +} + +list.dot = { + install_info = { + url = "https://github.com/rydesun/tree-sitter-dot", + files = { "src/parser.c" }, + }, + maintainers = { "@rydesun" }, +} + +list.doxygen = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-doxygen", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.dtd = { + install_info = { + url = "https://github.com/tree-sitter-grammars/tree-sitter-xml", + files = { "src/parser.c", "src/scanner.c" }, + location = "dtd", + }, + maintainers = { "@ObserverOfTime" }, +} + +list.earthfile = { + install_info = { + url = "https://github.com/glehmann/tree-sitter-earthfile", + files = { "src/parser.c" }, + }, + maintainers = { "@glehmann" }, +} + +list.ebnf = { + install_info = { + url = "https://github.com/RubixDev/ebnf", + files = { "src/parser.c" }, + location = "crates/tree-sitter-ebnf", + }, + maintainers = { "@RubixDev" }, + experimental = true, +} + +list.editorconfig = { + install_info = { + url = "https://github.com/ValdezFOmar/tree-sitter-editorconfig", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@ValdezFOmar" }, +} + +list.eds = { + install_info = { + url = "https://github.com/uyha/tree-sitter-eds", + files = { "src/parser.c" }, + }, + maintainers = { "@uyha" }, +} + +list.eex = { + install_info = { + url = "https://github.com/connorlay/tree-sitter-eex", + files = { "src/parser.c" }, + }, + filetype = "eelixir", + maintainers = { "@connorlay" }, +} + +list.elixir = { + install_info = { + url = "https://github.com/elixir-lang/tree-sitter-elixir", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@connorlay" }, +} + +list.elm = { + install_info = { + url = "https://github.com/elm-tooling/tree-sitter-elm", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@zweimach" }, +} + +list.elsa = { + install_info = { + url = "https://github.com/glapa-grossklag/tree-sitter-elsa", + files = { "src/parser.c" }, + }, + maintainers = { "@glapa-grossklag", "@amaanq" }, +} + +list.elvish = { + install_info = { + url = "https://github.com/elves/tree-sitter-elvish", + files = { "src/parser.c" }, + }, + maintainers = { "@elves" }, +} + +list.embedded_template = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-embedded-template", + files = { "src/parser.c" }, + }, + filetype = "eruby", +} + +list.erlang = { + install_info = { + url = "https://github.com/WhatsApp/tree-sitter-erlang", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@filmor" }, +} + +list.facility = { + install_info = { + url = "https://github.com/FacilityApi/tree-sitter-facility", + files = { "src/parser.c" }, + }, + filetype = "fsd", + maintainers = { "@bryankenote" }, +} + +list.faust = { + install_info = { + url = "https://github.com/khiner/tree-sitter-faust", + files = { "src/parser.c" }, + }, + filetype = "dsp", + maintainers = { "@khiner" }, +} + +list.fennel = { + install_info = { + url = "https://github.com/alexmozaidze/tree-sitter-fennel", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + maintainers = { "@alexmozaidze" }, +} + +list.fidl = { + install_info = { + url = "https://github.com/google/tree-sitter-fidl", + files = { "src/parser.c" }, + }, + maintainers = { "@chaopeng" }, +} + +list.firrtl = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-firrtl", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.fish = { + install_info = { + url = "https://github.com/ram02z/tree-sitter-fish", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@ram02z" }, +} + +list.foam = { + install_info = { + url = "https://github.com/FoamScience/tree-sitter-foam", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@FoamScience" }, + -- Queries might change over time on the grammar's side + -- Otherwise everything runs fine + experimental = true, +} + +list.forth = { + install_info = { + url = "https://github.com/AlexanderBrevig/tree-sitter-forth", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.fortran = { + install_info = { + url = "https://github.com/stadelmanma/tree-sitter-fortran", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.fsh = { + install_info = { + url = "https://github.com/mgramigna/tree-sitter-fsh", + files = { "src/parser.c" }, + }, + maintainers = { "@mgramigna" }, +} + +list.fsharp = { + install_info = { + url = "https://github.com/ionide/tree-sitter-fsharp", + files = { "src/parser.c", "src/scanner.c" }, + location = "fsharp", + }, + maintainers = { "@nsidorenco" }, +} + +list.func = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-func", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.fusion = { + install_info = { + url = "https://gitlab.com/jirgn/tree-sitter-fusion.git", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@jirgn" }, +} + +list.gap = { + install_info = { + url = "https://github.com/gap-system/tree-sitter-gap", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@reiniscirpons" }, + readme_name = "GAP system", +} + +list.gaptst = { + install_info = { + url = "https://github.com/gap-system/tree-sitter-gaptst", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@reiniscirpons" }, + readme_name = "GAP system test files", +} + +list.gdscript = { + install_info = { + url = "https://github.com/PrestonKnopp/tree-sitter-gdscript", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@PrestonKnopp" }, + readme_name = "Godot (gdscript)", +} + +list.gdshader = { + install_info = { + url = "https://github.com/GodOfAvacyn/tree-sitter-gdshader", + files = { "src/parser.c" }, + }, + filetype = "gdshaderinc", + maintainers = { "@godofavacyn" }, +} + +list.git_rebase = { + install_info = { + url = "https://github.com/the-mikedavis/tree-sitter-git-rebase", + files = { "src/parser.c" }, + }, + filetype = "gitrebase", + maintainers = { "@gbprod" }, +} + +list.gitattributes = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-gitattributes", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.gitcommit = { + install_info = { + url = "https://github.com/gbprod/tree-sitter-gitcommit", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@gbprod" }, +} + +list.git_config = { + install_info = { + url = "https://github.com/the-mikedavis/tree-sitter-git-config", + files = { "src/parser.c" }, + }, + filetype = "gitconfig", + maintainers = { "@amaanq" }, + readme_name = "git_config", +} + +list.gitignore = { + install_info = { + url = "https://github.com/shunsambongi/tree-sitter-gitignore", + files = { "src/parser.c" }, + }, + maintainers = { "@theHamsta" }, +} + +list.gleam = { + install_info = { + url = "https://github.com/gleam-lang/tree-sitter-gleam", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.glimmer = { + install_info = { + url = "https://github.com/ember-tooling/tree-sitter-glimmer", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "handlebars", + maintainers = { "@NullVoxPopuli" }, + readme_name = "Glimmer and Ember", +} + +list.glimmer_javascript = { + install_info = { + url = "https://github.com/NullVoxPopuli/tree-sitter-glimmer-javascript", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + filetype = "javascript.glimmer", + maintainers = { "@NullVoxPopuli" }, +} + +list.glimmer_typescript = { + install_info = { + url = "https://github.com/NullVoxPopuli/tree-sitter-glimmer-typescript", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + filetype = "typescript.glimmer", + maintainers = { "@NullVoxPopuli" }, +} + +list.glsl = { + install_info = { + url = "https://github.com/theHamsta/tree-sitter-glsl", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + maintainers = { "@theHamsta" }, +} + +list.gn = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-gn", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, + readme_name = "GN (Generate Ninja)", +} + +list.gnuplot = { + install_info = { + url = "https://github.com/dpezto/tree-sitter-gnuplot", + files = { "src/parser.c" }, + }, + maintainers = { "@dpezto" }, +} + +list.go = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-go", + files = { "src/parser.c" }, + }, + maintainers = { "@theHamsta", "@WinWisely268" }, +} + +list.goctl = { + install_info = { + url = "https://github.com/chaozwn/tree-sitter-goctl", + files = { "src/parser.c" }, + }, + maintainers = { "@chaozwn" }, +} + +list.godot_resource = { + install_info = { + url = "https://github.com/PrestonKnopp/tree-sitter-godot-resource", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "gdresource", + maintainers = { "@pierpo" }, + readme_name = "Godot Resources (gdresource)", +} + +list.gomod = { + install_info = { + url = "https://github.com/camdencheek/tree-sitter-go-mod", + files = { "src/parser.c" }, + }, + maintainers = { "@camdencheek" }, +} + +list.gosum = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-go-sum", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.gowork = { + install_info = { + url = "https://github.com/omertuc/tree-sitter-go-work", + files = { "src/parser.c" }, + }, + maintainers = { "@omertuc" }, +} + +list.gotmpl = { + install_info = { + url = "https://github.com/ngalaiko/tree-sitter-go-template", + files = { "src/parser.c" }, + }, + maintainers = { "@qvalentin" }, +} + +list.gpg = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-gpg-config", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.gren = { + install_info = { + files = { "src/parser.c", "src/scanner.c" }, + url = "https://github.com/MaeBrooks/tree-sitter-gren", + }, + maintainers = { "@MaeBrooks" }, +} + +list.groovy = { + install_info = { + url = "https://github.com/murtaza64/tree-sitter-groovy", + files = { "src/parser.c" }, + }, + maintainers = { "@murtaza64" }, +} + +list.graphql = { + install_info = { + url = "https://github.com/bkegley/tree-sitter-graphql", + files = { "src/parser.c" }, + }, + maintainers = { "@bkegley" }, +} + +list.gstlaunch = { + install_info = { + url = "https://github.com/theHamsta/tree-sitter-gstlaunch", + files = { "src/parser.c" }, + }, + maintainers = { "@theHamsta" }, +} + +list.hack = { + install_info = { + url = "https://github.com/slackhq/tree-sitter-hack", + files = { "src/parser.c", "src/scanner.c" }, + }, +} + +list.hare = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-hare", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.haskell = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-haskell", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@mrcjkb" }, +} + +list.haskell_persistent = { + install_info = { + url = "https://github.com/MercuryTechnologies/tree-sitter-haskell-persistent", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "haskellpersistent", + maintainers = { "@lykahb" }, +} + +list.hcl = { + install_info = { + url = "https://github.com/MichaHoffmann/tree-sitter-hcl", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@MichaHoffmann" }, +} + +list.heex = { + install_info = { + url = "https://github.com/connorlay/tree-sitter-heex", + files = { "src/parser.c" }, + }, + maintainers = { "@connorlay" }, +} + +list.helm = { + install_info = { + url = "https://github.com/ngalaiko/tree-sitter-go-template", + location = "dialects/helm", + files = { "src/parser.c" }, + }, + maintainers = { "@qvalentin" }, +} + +list.hjson = { + install_info = { + url = "https://github.com/winston0410/tree-sitter-hjson", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + maintainers = { "@winston0410" }, +} + +list.hlsl = { + install_info = { + url = "https://github.com/theHamsta/tree-sitter-hlsl", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + maintainers = { "@theHamsta" }, +} + +list.hocon = { + install_info = { + url = "https://github.com/antosha417/tree-sitter-hocon", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + maintainers = { "@antosha417" }, +} + +list.hoon = { + install_info = { + url = "https://github.com/urbit-pilled/tree-sitter-hoon", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@urbit-pilled" }, + experimental = true, +} + +list.html = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-html", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@TravonteD" }, +} + +list.htmldjango = { + install_info = { + url = "https://github.com/interdependence/tree-sitter-htmldjango", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, + experimental = true, +} + +list.http = { + install_info = { + url = "https://github.com/rest-nvim/tree-sitter-http", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq", "@NTBBloodbath" }, +} + +list.hurl = { + install_info = { + url = "https://github.com/pfeiferj/tree-sitter-hurl", + files = { "src/parser.c" }, + }, + maintainers = { "@pfeiferj" }, +} + +list.hyprlang = { + install_info = { + url = "https://github.com/luckasRanarison/tree-sitter-hyprlang", + files = { "src/parser.c" }, + }, + maintainers = { "@luckasRanarison" }, +} + +list.idl = { + install_info = { + url = "https://github.com/cathaysia/tree-sitter-idl", + files = { "src/parser.c" }, + }, + maintainers = { "@cathaysia" }, +} + +list.ini = { + install_info = { + url = "https://github.com/justinmk/tree-sitter-ini", + files = { "src/parser.c" }, + }, + maintainers = { "@theHamsta" }, + experimental = true, +} + +list.inko = { + install_info = { + url = "https://github.com/inko-lang/tree-sitter-inko", + files = { "src/parser.c" }, + }, + maintainers = { "@yorickpeterse" }, +} + +list.ispc = { + install_info = { + url = "https://github.com/fab4100/tree-sitter-ispc", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + maintainers = { "@fab4100" }, +} + +list.janet_simple = { + install_info = { + url = "https://github.com/sogaiu/tree-sitter-janet-simple", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "janet", + maintainers = { "@sogaiu" }, +} + +list.java = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-java", + files = { "src/parser.c" }, + }, + maintainers = { "@p00f" }, +} + +list.javascript = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-javascript", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@steelsojka" }, +} + +list.jq = { + install_info = { + url = "https://github.com/flurie/tree-sitter-jq", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.jsdoc = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-jsdoc", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@steelsojka" }, +} + +list.json = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-json", + files = { "src/parser.c" }, + }, + maintainers = { "@steelsojka" }, +} + +list.json5 = { + install_info = { + url = "https://github.com/Joakker/tree-sitter-json5", + files = { "src/parser.c" }, + }, + maintainers = { "@Joakker" }, +} + +list.jsonc = { + install_info = { + url = "https://gitlab.com/WhyNotHugo/tree-sitter-jsonc.git", + files = { "src/parser.c" }, + generate_requires_npm = true, + }, + maintainers = { "@WhyNotHugo" }, + readme_name = "JSON with comments", +} + +list.jsonnet = { + install_info = { + url = "https://github.com/sourcegraph/tree-sitter-jsonnet", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@nawordar" }, +} + +list.julia = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-julia", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@theHamsta" }, +} + +list.just = { + install_info = { + url = "https://github.com/IndianBoy42/tree-sitter-just", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@Hubro" }, +} + +list.kconfig = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-kconfig", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.kdl = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-kdl", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.kotlin = { + install_info = { + url = "https://github.com/fwcd/tree-sitter-kotlin", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@SalBakraa" }, +} + +list.koto = { + install_info = { + url = "https://github.com/koto-lang/tree-sitter-koto", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@irh" }, +} + +list.kusto = { + install_info = { + url = "https://github.com/Willem-J-an/tree-sitter-kusto", + files = { "src/parser.c" }, + }, + maintainers = { "@Willem-J-an" }, +} + +list.lalrpop = { + install_info = { + url = "https://github.com/traxys/tree-sitter-lalrpop", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@traxys" }, +} + +list.latex = { + install_info = { + url = "https://github.com/latex-lsp/tree-sitter-latex", + files = { "src/parser.c", "src/scanner.c" }, + requires_generate_from_grammar = true, + }, + filetype = "tex", + maintainers = { "@theHamsta", "@clason" }, +} + +list.ledger = { + install_info = { + url = "https://github.com/cbarrete/tree-sitter-ledger", + files = { "src/parser.c" }, + }, + maintainers = { "@cbarrete" }, +} + +list.leo = { + install_info = { + url = "https://github.com/r001/tree-sitter-leo", + files = { "src/parser.c" }, + }, + maintainers = { "@r001" }, +} + +list.llvm = { + install_info = { + url = "https://github.com/benwilliamgraham/tree-sitter-llvm", + files = { "src/parser.c" }, + }, + maintainers = { "@benwilliamgraham" }, +} + +list.linkerscript = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-linkerscript", + files = { "src/parser.c" }, + }, + filetype = "ld", + maintainers = { "@amaanq" }, +} + +list.liquid = { + install_info = { + url = "https://github.com/hankthetank27/tree-sitter-liquid", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@hankthetank27" }, +} + +list.liquidsoap = { + install_info = { + url = "https://github.com/savonet/tree-sitter-liquidsoap", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@toots" }, +} + +list.lua = { + install_info = { + url = "https://github.com/MunifTanjim/tree-sitter-lua", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@muniftanjim" }, +} + +list.luadoc = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-luadoc", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.luap = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-luap", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, + readme_name = "lua patterns", +} + +list.luau = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-luau", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.hlsplaylist = { + install_info = { + url = "https://github.com/Freed-Wu/tree-sitter-hlsplaylist", + files = { "src/parser.c" }, + }, + maintainers = { "@Freed-Wu" }, +} + +list.m68k = { + install_info = { + url = "https://github.com/grahambates/tree-sitter-m68k", + files = { "src/parser.c" }, + }, + filetype = "asm68k", + maintainers = { "@grahambates" }, +} + +list.make = { + install_info = { + url = "https://github.com/alemuller/tree-sitter-make", + files = { "src/parser.c" }, + }, + maintainers = { "@lewis6991" }, +} + +list.markdown = { + install_info = { + url = "https://github.com/MDeiml/tree-sitter-markdown", + location = "tree-sitter-markdown", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@MDeiml" }, + readme_name = "markdown (basic highlighting)", + 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.c" }, + }, + maintainers = { "@MDeiml" }, + readme_name = "markdown_inline (needed for full highlighting)", + experimental = true, +} + +list.matlab = { + install_info = { + url = "https://github.com/acristoffers/tree-sitter-matlab", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@acristoffers" }, +} + +list.menhir = { + install_info = { + url = "https://github.com/Kerl13/tree-sitter-menhir", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@Kerl13" }, +} + +list.mermaid = { + install_info = { + url = "https://github.com/monaqa/tree-sitter-mermaid", + files = { "src/parser.c" }, + }, + experimental = true, +} + +list.meson = { + install_info = { + url = "https://github.com/Decodetalkers/tree-sitter-meson", + files = { "src/parser.c" }, + }, + maintainers = { "@Decodetalkers" }, +} + +list.mlir = { + install_info = { + url = "https://github.com/artagnon/tree-sitter-mlir", + files = { "src/parser.c" }, + requires_generate_from_grammar = true, + }, + experimental = true, + maintainers = { "@artagnon" }, +} + +list.muttrc = { + install_info = { + url = "https://github.com/neomutt/tree-sitter-muttrc", + files = { "src/parser.c" }, + }, + maintainers = { "@Freed-Wu" }, +} + +list.nasm = { + install_info = { + url = "https://github.com/naclsn/tree-sitter-nasm", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.nginx = { + install_info = { + url = "https://github.com/opa-oz/tree-sitter-nginx", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@opa-oz" }, +} + +list.nickel = { + install_info = { + url = "https://github.com/nickel-lang/tree-sitter-nickel", + files = { "src/parser.c", "src/scanner.c" }, + }, +} + +list.nim = { + install_info = { + url = "https://github.com/alaviss/tree-sitter-nim", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@aMOPel" }, +} + +list.nim_format_string = { + install_info = { + url = "https://github.com/aMOPel/tree-sitter-nim-format-string", + files = { "src/parser.c" }, + }, + maintainers = { "@aMOPel" }, +} + +list.ninja = { + install_info = { + url = "https://github.com/alemuller/tree-sitter-ninja", + files = { "src/parser.c" }, + }, + maintainers = { "@alemuller" }, +} + +list.nix = { + install_info = { + url = "https://github.com/cstrahan/tree-sitter-nix", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@leo60228" }, +} + +list.norg = { + install_info = { + url = "https://github.com/nvim-neorg/tree-sitter-norg", + files = { "src/parser.c", "src/scanner.cc" }, + cxx_standard = "c++14", + use_makefile = true, + }, + maintainers = { "@JoeyGrajciar", "@vhyrro" }, +} + +list.nqc = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-nqc", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.objc = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-objc", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.objdump = { + install_info = { + url = "https://github.com/ColinKennedy/tree-sitter-objdump", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@ColinKennedy" }, +} + +list.ocaml = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-ocaml", + files = { "src/parser.c", "src/scanner.c" }, + location = "grammars/ocaml", + }, + maintainers = { "@undu" }, +} + +list.ocaml_interface = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-ocaml", + files = { "src/parser.c", "src/scanner.c" }, + location = "grammars/interface", + }, + filetype = "ocamlinterface", + maintainers = { "@undu" }, +} + +list.ocamllex = { + install_info = { + url = "https://github.com/atom-ocaml/tree-sitter-ocamllex", + files = { "src/parser.c", "src/scanner.c" }, + requires_generate_from_grammar = true, + }, + maintainers = { "@undu" }, +} + +list.odin = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-odin", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.org = { + install_info = { + url = "https://github.com/milisims/tree-sitter-org", + files = { "src/parser.c", "src/scanner.c" }, + }, +} + +list.pascal = { + install_info = { + url = "https://github.com/Isopod/tree-sitter-pascal", + files = { "src/parser.c" }, + }, + maintainers = { "@Isopod" }, +} + +list.passwd = { + install_info = { + url = "https://github.com/ath3/tree-sitter-passwd", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.pem = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-pem", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.perl = { + install_info = { + url = "https://github.com/tree-sitter-perl/tree-sitter-perl", + files = { "src/parser.c", "src/scanner.c" }, + branch = "release", + }, + maintainers = { "@RabbiVeesh", "@LeoNerd" }, +} + +list.php = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-php", + location = "php", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@tk-shirasaka", "@calebdw" }, +} + +list.php_only = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-php", + location = "php_only", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@tk-shirasaka", "@calebdw" }, +} + +-- 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.pioasm = { + install_info = { + url = "https://github.com/leo60228/tree-sitter-pioasm", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@leo60228" }, +} + +list.po = { + install_info = { + url = "https://github.com/erasin/tree-sitter-po", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.pod = { + install_info = { + url = "https://github.com/tree-sitter-perl/tree-sitter-pod", + files = { "src/parser.c", "src/scanner.c" }, + branch = "release", + }, + maintainers = { "@RabbiVeesh", "@LeoNerd" }, +} + +list.poe_filter = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-poe-filter", + files = { "src/parser.c" }, + }, + filetype = "poefilter", + maintainers = { "@ObserverOfTime" }, + readme_name = "Path of Exile item filter", + experimental = true, +} + +list.pony = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-pony", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq", "@mfelsche" }, +} + +list.powershell = { + install_info = { + url = "https://github.com/airbus-cert/tree-sitter-powershell", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "ps1", + maintainers = { "@L2jLiga" }, +} + +list.printf = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-printf", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.prisma = { + install_info = { + url = "https://github.com/victorhqc/tree-sitter-prisma", + files = { "src/parser.c" }, + }, + maintainers = { "@elianiva" }, +} + +list.problog = { + install_info = { + url = "https://github.com/foxyseta/tree-sitter-prolog", + files = { "src/parser.c" }, + location = "grammars/problog", + }, + maintainers = { "@foxyseta" }, +} + +list.prolog = { + install_info = { + url = "https://github.com/foxyseta/tree-sitter-prolog", + files = { "src/parser.c" }, + location = "grammars/prolog", + }, + maintainers = { "@foxyseta" }, +} + +list.promql = { + install_info = { + url = "https://github.com/MichaHoffmann/tree-sitter-promql", + files = { "src/parser.c" }, + experimental = true, + }, + maintainers = { "@MichaHoffmann" }, +} + +list.properties = { + install_info = { + url = "https://github.com/tree-sitter-grammars/tree-sitter-properties", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "jproperties", + maintainers = { "@ObserverOfTime" }, +} + +list.proto = { + install_info = { + url = "https://github.com/treywood/tree-sitter-proto", + files = { "src/parser.c" }, + }, + maintainers = { "@treywood" }, +} + +list.prql = { + install_info = { + url = "https://github.com/PRQL/tree-sitter-prql", + files = { "src/parser.c" }, + }, + maintainers = { "@matthias-Q" }, +} + +list.psv = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-csv", + files = { "src/parser.c" }, + location = "psv", + }, + maintainers = { "@amaanq" }, +} + +list.pug = { + install_info = { + url = "https://github.com/zealot128/tree-sitter-pug", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@zealot128" }, + experimental = true, +} + +list.puppet = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-puppet", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.purescript = { + install_info = { + url = "https://github.com/postsolar/tree-sitter-purescript", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@postsolar" }, +} + +list.pymanifest = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-pymanifest", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, + readme_name = "PyPA manifest", +} + +list.python = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-python", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@stsewd", "@theHamsta" }, +} + +list.ql = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-ql", + files = { "src/parser.c" }, + }, + maintainers = { "@pwntester" }, +} + +list.qmldir = { + install_info = { + url = "https://github.com/Decodetalkers/tree-sitter-qmldir", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.qmljs = { + install_info = { + url = "https://github.com/yuja/tree-sitter-qmljs", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "qml", + maintainers = { "@Decodetalkers" }, +} + +list.query = { + install_info = { + url = "https://github.com/nvim-treesitter/tree-sitter-query", + files = { "src/parser.c" }, + }, + maintainers = { "@steelsojka" }, + readme_name = "Tree-Sitter query language", +} + +list.r = { + install_info = { + url = "https://github.com/r-lib/tree-sitter-r", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@ribru17" }, +} + +list.racket = { + install_info = { + url = "https://github.com/6cdh/tree-sitter-racket", + files = { "src/parser.c", "src/scanner.c" }, + }, +} + +list.ralph = { + install_info = { + url = "https://github.com/alephium/tree-sitter-ralph", + files = { "src/parser.c" }, + }, + maintainers = { "@tdroxler" }, +} + +list.rasi = { + install_info = { + url = "https://github.com/Fymyte/tree-sitter-rasi", + files = { "src/parser.c" }, + }, + maintainers = { "@Fymyte" }, +} + +list.rbs = { + install_info = { + url = "https://github.com/joker1007/tree-sitter-rbs", + files = { "src/parser.c" }, + }, + maintainers = { "@joker1007" }, +} + +list.re2c = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-re2c", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.readline = { + install_info = { + url = "https://github.com/ribru17/tree-sitter-readline", + files = { "src/parser.c" }, + }, + maintainers = { "@ribru17" }, +} + +list.regex = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-regex", + files = { "src/parser.c" }, + }, + maintainers = { "@theHamsta" }, +} + +list.rego = { + install_info = { + url = "https://github.com/FallenAngel97/tree-sitter-rego", + files = { "src/parser.c" }, + }, + maintainers = { "@FallenAngel97" }, +} + +list.requirements = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-requirements", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, + readme_name = "pip requirements", +} + +list.rescript = { + install_info = { + url = "https://github.com/rescript-lang/tree-sitter-rescript", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@ribru17" }, +} + +list.rnoweb = { + install_info = { + url = "https://github.com/bamonroe/tree-sitter-rnoweb", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@bamonroe" }, +} + +list.robot = { + install_info = { + url = "https://github.com/Hubro/tree-sitter-robot", + files = { "src/parser.c" }, + }, + maintainers = { "@Hubro" }, +} + +list.robots = { + install_info = { + url = "https://github.com/opa-oz/tree-sitter-robots-txt", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@opa-oz" }, +} + +list.roc = { + install_info = { + url = "https://github.com/faldor20/tree-sitter-roc", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@nat-418" }, +} + +list.ron = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-ron", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.rst = { + install_info = { + url = "https://github.com/stsewd/tree-sitter-rst", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@stsewd" }, +} + +list.ruby = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-ruby", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@TravonteD" }, +} + +list.rust = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-rust", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.scala = { + install_info = { + url = "https://github.com/tree-sitter/tree-sitter-scala", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@stevanmilic" }, +} + +list.scfg = { + install_info = { + url = "https://github.com/rockorager/tree-sitter-scfg", + files = { "src/parser.c" }, + requires_generate_from_grammar = true, + }, + maintainers = { "@WhyNotHugo" }, +} + +list.scheme = { + install_info = { + url = "https://github.com/6cdh/tree-sitter-scheme", + files = { "src/parser.c" }, + }, +} + +list.scss = { + install_info = { + url = "https://github.com/serenadeai/tree-sitter-scss", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@elianiva" }, +} + +list.sflog = { + install_info = { + url = "https://github.com/aheber/tree-sitter-sfapex", + files = { "src/parser.c" }, + location = "sflog", + }, + maintainers = { "@aheber", "@xixiaofinland" }, +} + +list.slang = { + install_info = { + url = "https://github.com/theHamsta/tree-sitter-slang", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + filetype = "shaderslang", + maintainers = { "@theHamsta" }, + experimental = true, +} + +list.slint = { + install_info = { + url = "https://github.com/slint-ui/tree-sitter-slint", + files = { "src/parser.c" }, + }, + maintainers = { "@hunger" }, +} + +list.smali = { + install_info = { + url = "https://github.com/tree-sitter-grammars/tree-sitter-smali", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.snakemake = { + install_info = { + url = "https://github.com/osthomas/tree-sitter-snakemake", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainer = { "@osthomas" }, + experimental = true, +} + +list.smithy = { + install_info = { + url = "https://github.com/indoorvivants/tree-sitter-smithy", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq", "@keynmol" }, +} + +list.solidity = { + install_info = { + url = "https://github.com/JoranHonig/tree-sitter-solidity", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.soql = { + install_info = { + url = "https://github.com/aheber/tree-sitter-sfapex", + files = { "src/parser.c" }, + location = "soql", + }, + maintainers = { "@aheber", "@xixiaofinland" }, +} + +list.sosl = { + install_info = { + url = "https://github.com/aheber/tree-sitter-sfapex", + files = { "src/parser.c" }, + location = "sosl", + }, + maintainers = { "@aheber", "@xixiaofinland" }, +} + +list.sourcepawn = { + install_info = { + url = "https://github.com/nilshelmig/tree-sitter-sourcepawn", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@Sarrus1" }, + tier = 3, +} + +list.sparql = { + install_info = { + url = "https://github.com/GordianDziwis/tree-sitter-sparql", + files = { "src/parser.c" }, + }, + maintainers = { "@GordianDziwis" }, +} + +list.sql = { + install_info = { + url = "https://github.com/derekstride/tree-sitter-sql", + files = { "src/parser.c", "src/scanner.c" }, + branch = "gh-pages", + }, + maintainers = { "@derekstride" }, +} + +list.squirrel = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-squirrel", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.ssh_config = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-ssh-config", + files = { "src/parser.c" }, + }, + filetype = "sshconfig", + maintainers = { "@ObserverOfTime" }, +} + +list.starlark = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-starlark", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "bzl", + maintainers = { "@amaanq" }, +} + +list.strace = { + install_info = { + url = "https://github.com/sigmaSd/tree-sitter-strace", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.styled = { + install_info = { + url = "https://github.com/mskelton/tree-sitter-styled", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@mskelton" }, +} + +list.supercollider = { + install_info = { + url = "https://github.com/madskjeldgaard/tree-sitter-supercollider", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@madskjeldgaard" }, +} + +list.superhtml = { + install_info = { + url = "https://github.com/kristoff-it/superhtml", + files = { + "src/parser.c", + "src/scanner.c", + }, + location = "tree-sitter-superhtml", + }, + maintainers = { "@rockorager" }, +} + +list.surface = { + install_info = { + url = "https://github.com/connorlay/tree-sitter-surface", + files = { "src/parser.c" }, + }, + filetype = "sface", + maintainers = { "@connorlay" }, +} + +list.svelte = { + install_info = { + url = "https://github.com/tree-sitter-grammars/tree-sitter-svelte", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.swift = { + install_info = { + url = "https://github.com/alex-pinkus/tree-sitter-swift", + files = { "src/parser.c", "src/scanner.c" }, + requires_generate_from_grammar = true, + }, + maintainers = { "@alex-pinkus" }, +} + +list.sxhkdrc = { + install_info = { + url = "https://github.com/RaafatTurki/tree-sitter-sxhkdrc", + files = { "src/parser.c" }, + }, + maintainers = { "@RaafatTurki" }, +} + +list.systemtap = { + install_info = { + url = "https://github.com/ok-ryoko/tree-sitter-systemtap", + files = { "src/parser.c" }, + }, + maintainers = { "@ok-ryoko" }, +} + +list.t32 = { + install_info = { + url = "https://gitlab.com/xasc/tree-sitter-t32.git", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "trace32", + maintainers = { "@xasc" }, +} + +list.tablegen = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-tablegen", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.tact = { + install_info = { + url = "https://github.com/tact-lang/tree-sitter-tact", + files = { "src/parser.c" }, + }, + maintainers = { "@novusnota" }, +} + +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.tcl = { + install_info = { + url = "https://github.com/tree-sitter-grammars/tree-sitter-tcl", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@lewis6991" }, +} + +list.terraform = { + install_info = { + url = "https://github.com/MichaHoffmann/tree-sitter-hcl", + files = { "src/parser.c", "src/scanner.c" }, + location = "dialects/terraform", + }, + maintainers = { "@MichaHoffmann" }, +} + +list.textproto = { + install_info = { + url = "https://github.com/PorterAtGoogle/tree-sitter-textproto", + files = { "src/parser.c" }, + }, + filetype = "pbtxt", + maintainers = { "@Porter" }, +} + +list.thrift = { + install_info = { + url = "https://github.com/duskmoon314/tree-sitter-thrift", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq", "@duskmoon314" }, +} + +list.tiger = { + install_info = { + url = "https://github.com/ambroisie/tree-sitter-tiger", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@ambroisie" }, +} + +list.tlaplus = { + install_info = { + url = "https://github.com/tlaplus-community/tree-sitter-tlaplus", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "tla", + maintainers = { "@ahelwer", "@susliko" }, +} + +list.tmux = { + install_info = { + url = "https://github.com/Freed-Wu/tree-sitter-tmux", + files = { "src/parser.c" }, + }, + maintainers = { "@Freed-Wu" }, +} + +list.todotxt = { + install_info = { + url = "https://github.com/arnarg/tree-sitter-todotxt", + files = { "src/parser.c" }, + }, + maintainers = { "@arnarg" }, + experimental = true, +} + +list.toml = { + install_info = { + url = "https://github.com/tree-sitter-grammars/tree-sitter-toml", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + maintainers = { "@tk-shirasaka" }, +} + +list.tsv = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-csv", + files = { "src/parser.c" }, + location = "tsv", + }, + maintainers = { "@amaanq" }, +} + +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.turtle = { + install_info = { + url = "https://github.com/GordianDziwis/tree-sitter-turtle", + files = { "src/parser.c" }, + }, + maintainers = { "@GordianDziwis" }, +} + +list.twig = { + install_info = { + url = "https://github.com/gbprod/tree-sitter-twig", + files = { "src/parser.c" }, + }, + maintainers = { "@gbprod" }, +} + +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.typespec = { + install_info = { + url = "https://github.com/happenslol/tree-sitter-typespec", + files = { "src/parser.c" }, + }, + maintainers = { "@happenslol" }, +} + +list.typoscript = { + install_info = { + url = "https://github.com/Teddytrombone/tree-sitter-typoscript", + files = { "src/parser.c" }, + }, + maintainers = { "@Teddytrombone" }, +} + +list.typst = { + install_info = { + url = "https://github.com/uben0/tree-sitter-typst", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@uben0", "@RaafatTurki" }, +} + +list.udev = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-udev", + files = { "src/parser.c" }, + }, + filetype = "udevrules", + maintainers = { "@ObserverOfTime" }, +} + +list.ungrammar = { + install_info = { + url = "https://github.com/Philipp-M/tree-sitter-ungrammar", + files = { "src/parser.c" }, + }, + maintainers = { "@Philipp-M", "@amaanq" }, +} + +list.unison = { + install_info = { + url = "https://github.com/kylegoetz/tree-sitter-unison", + files = { "src/parser.c", "src/scanner.c" }, + requires_generate_from_grammar = true, + }, + maintainers = { "@tapegram" }, +} + +list.usd = { + install_info = { + url = "https://github.com/ColinKennedy/tree-sitter-usd", + files = { "src/parser.c" }, + }, + maintainers = { "@ColinKennedy" }, +} + +list.uxntal = { + install_info = { + url = "https://github.com/amaanq/tree-sitter-uxntal", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "tal", + maintainers = { "@amaanq" }, + readme_name = "uxn tal", +} + +list.v = { + install_info = { + url = "https://github.com/vlang/v-analyzer", + files = { "src/parser.c" }, + location = "tree_sitter_v", + }, + filetype = "vlang", + maintainers = { "@kkharji", "@amaanq" }, +} + +list.vala = { + install_info = { + url = "https://github.com/vala-lang/tree-sitter-vala", + files = { "src/parser.c" }, + }, + maintainers = { "@Prince781" }, +} + +list.vento = { + install_info = { + url = "https://github.com/ventojs/tree-sitter-vento", + files = { "src/parser.c", "src/scanner.c" }, + }, + filetype = "vto", + maintainers = { "@wrapperup", "@oscarotero" }, +} + +list.verilog = { + install_info = { + url = "https://github.com/gmlarumbe/tree-sitter-systemverilog", + files = { "src/parser.c" }, + }, + maintainers = { "@zhangwwpeng" }, +} + +list.vhdl = { + install_info = { + url = "https://github.com/jpt13653903/tree-sitter-vhdl", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@jpt13653903" }, +} + +list.vhs = { + install_info = { + url = "https://github.com/charmbracelet/tree-sitter-vhs", + files = { "src/parser.c" }, + }, + filetype = "tape", + maintainers = { "@caarlos0" }, +} + +list.vim = { + install_info = { + url = "https://github.com/neovim/tree-sitter-vim", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@clason" }, +} + +list.vimdoc = { + install_info = { + url = "https://github.com/neovim/tree-sitter-vimdoc", + files = { "src/parser.c" }, + }, + filetype = "help", + maintainers = { "@clason" }, +} + +list.vrl = { + install_info = { + url = "https://github.com/belltoy/tree-sitter-vrl", + files = { "src/parser.c" }, + }, + maintainers = { "@belltoy" }, +} + +list.vue = { + install_info = { + url = "https://github.com/tree-sitter-grammars/tree-sitter-vue", + files = { "src/parser.c", "src/scanner.c" }, + branch = "main", + }, + maintainers = { "@WhyNotHugo", "@lucario387" }, +} + +list.wgsl = { + install_info = { + url = "https://github.com/szebniok/tree-sitter-wgsl", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@szebniok" }, +} + +list.wgsl_bevy = { + install_info = { + url = "https://github.com/theHamsta/tree-sitter-wgsl-bevy", + files = { "src/parser.c", "src/scanner.c" }, + generate_requires_npm = true, + }, + maintainers = { "@theHamsta" }, +} + +list.wing = { + install_info = { + url = "https://github.com/winglang/tree-sitter-wing", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@gshpychka", "@MarkMcCulloh" }, +} + +list.wit = { + install_info = { + url = "https://github.com/liamwh/tree-sitter-wit", + files = { "src/parser.c" }, + }, + maintainers = { "@liamwh" }, +} + +list.xcompose = { + install_info = { + url = "https://github.com/ObserverOfTime/tree-sitter-xcompose", + files = { "src/parser.c" }, + }, + maintainers = { "@ObserverOfTime" }, +} + +list.xml = { + install_info = { + url = "https://github.com/tree-sitter-grammars/tree-sitter-xml", + files = { "src/parser.c", "src/scanner.c" }, + location = "xml", + }, + maintainers = { "@ObserverOfTime" }, +} + +list.xresources = { + install_info = { + url = "https://github.com/ValdezFOmar/tree-sitter-xresources", + files = { "src/parser.c" }, + }, + filetype = "xdefaults", + maintainers = { "@ValdezFOmar" }, +} + +list.yaml = { + install_info = { + url = "https://github.com/tree-sitter-grammars/tree-sitter-yaml", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.yang = { + install_info = { + url = "https://github.com/Hubro/tree-sitter-yang", + files = { "src/parser.c" }, + }, + maintainers = { "@Hubro" }, +} + +list.yuck = { + install_info = { + url = "https://github.com/Philipp-M/tree-sitter-yuck", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@Philipp-M", "@amaanq" }, +} + +list.zathurarc = { + install_info = { + url = "https://github.com/Freed-Wu/tree-sitter-zathurarc", + files = { "src/parser.c" }, + }, + maintainers = { "@Freed-Wu" }, +} + +list.zig = { + install_info = { + url = "https://github.com/tree-sitter-grammars/tree-sitter-zig", + files = { "src/parser.c" }, + }, + maintainers = { "@amaanq" }, +} + +list.ziggy = { + install_info = { + url = "https://github.com/kristoff-it/ziggy", + files = { "src/parser.c" }, + location = "tree-sitter-ziggy", + }, + maintainers = { "@rockorager" }, +} + +list.ziggy_schema = { + install_info = { + url = "https://github.com/kristoff-it/ziggy", + files = { "src/parser.c" }, + location = "tree-sitter-ziggy-schema", + }, + maintainers = { "@rockorager" }, +} + +list.templ = { + install_info = { + url = "https://github.com/vrischmann/tree-sitter-templ", + files = { "src/parser.c", "src/scanner.c" }, + }, + maintainers = { "@vrischmann" }, +} + +local M = { + list = list, +} + +function M.ft_to_lang(ft) + local result = ts.language.get_lang(ft) + if result then + return result + else + ft = vim.split(ft, ".", { plain = true })[1] + return ts.language.get_lang(ft) or ft + end +end + +-- Get a list of all available parsers +---@return string[] +function M.available_parsers() + local parsers = vim.tbl_keys(M.list) + table.sort(parsers) + if vim.fn.executable "tree-sitter" == 1 and vim.fn.executable "node" == 1 then + return parsers + else + return vim.tbl_filter(function(p) ---@param p string + return not M.list[p].install_info.requires_generate_from_grammar + end, parsers) + 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 + +-- Gets the language of a given buffer +---@param bufnr number? or current buffer +---@return string +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..4aba9f2fd --- /dev/null +++ b/lua/nvim-treesitter/query.lua @@ -0,0 +1,453 @@ +local api = vim.api +local ts = require "nvim-treesitter.compat" +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 fun(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 + + ---@param bufnr integer + ---@param query_group string + ---@return any + 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 + ---@type table> + 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] = ts.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 TSNode +---@field source integer +---@field start integer +---@field stop integer + +---@param bufnr integer +---@param query_name string +---@param root TSNode +---@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 + +-- Given a path (i.e. a List(String)) this functions inserts value at path +---@param object any +---@param path string[] +---@param value any +function M.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 + +---@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 '.' + ---@param to_split string + ---@return string[] + local function split(to_split) + local t = {} + for str in string.gmatch(to_split, "([^.]+)") do + table.insert(t, str) + end + + return t + end + + local matches = query:iter_matches(qnode, bufnr, start_row, end_row, { all = false }) + + 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") + M.insert_to_path(prepared_match, path, node) + local metadata_path = split(name .. ".metadata") + M.insert_to_path(prepared_match, metadata_path, metadata[id]) + end + end + + -- Add some predicates for testing + ---@type string[][] ( TODO: make pred type so this can be pred[]) + 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 + M.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 + M.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 TSNode|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 = {} ---@type string[] + 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 + +---@param bufnr integer +---@param capture_string string +---@param query_group string +---@param filter_predicate fun(match: table): boolean +---@param scoring_function fun(match: table): number +---@param root TSNode +---@return table|unknown +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 ---@type table|nil + local best_score ---@type number + + 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 TSNode the root node +---@param root_lang? string 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 buffer +---@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 ignored if a function is provided +--- for the capture argument. +---@return table[] +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) or {}) + 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..5caaaa8b8 --- /dev/null +++ b/lua/nvim-treesitter/query_predicates.lua @@ -0,0 +1,241 @@ +local query = require "vim.treesitter.query" + +local html_script_type_languages = { + ["importmap"] = "json", + ["module"] = "javascript", + ["application/ecmascript"] = "javascript", + ["text/ecmascript"] = "javascript", +} + +local non_filetype_match_injection_language_aliases = { + ex = "elixir", + pl = "perl", + sh = "bash", + uxn = "uxntal", + ts = "typescript", +} + +-- compatibility shim for breaking change on nightly/0.11 +local opts = vim.fn.has "nvim-0.10" == 1 and { force = true, all = false } or true + +local function get_parser_from_markdown_info_string(injection_alias) + local match = vim.filetype.match { filename = "a." .. injection_alias } + return match or non_filetype_match_injection_language_aliases[injection_alias] or injection_alias +end + +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 + +---@param match (TSNode|nil)[] +---@param _pattern string +---@param _bufnr integer +---@param pred string[] +---@return boolean|nil +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]] ---@type TSNode + 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, opts) + +---@param match (TSNode|nil)[] +---@param _pattern string +---@param _bufnr integer +---@param pred string[] +---@return boolean|nil +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, opts) + +query.add_predicate("has-parent?", has_ancestor, opts) + +---@param match (TSNode|nil)[] +---@param _pattern string +---@param bufnr integer +---@param pred string[] +---@return boolean|nil +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, opts) + +---@param match (TSNode|nil)[] +---@param _pattern string +---@param _bufnr integer +---@param pred string[] +---@return boolean|nil +query.add_predicate("kind-eq?", 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, opts) + +---@param match (TSNode|nil)[] +---@param _ string +---@param bufnr integer +---@param pred string[] +---@return boolean|nil +query.add_directive("set-lang-from-mimetype!", function(match, _, bufnr, pred, metadata) + local capture_id = pred[2] + local node = match[capture_id] + if not node then + return + end + local type_attr_value = vim.treesitter.get_node_text(node, bufnr) + local configured = html_script_type_languages[type_attr_value] + if configured then + metadata["injection.language"] = configured + else + local parts = vim.split(type_attr_value, "/", {}) + metadata["injection.language"] = parts[#parts] + end +end, opts) + +---@param match (TSNode|nil)[] +---@param _ string +---@param bufnr integer +---@param pred string[] +---@return boolean|nil +query.add_directive("set-lang-from-info-string!", function(match, _, bufnr, pred, metadata) + local capture_id = pred[2] + local node = match[capture_id] + if not node then + return + end + local injection_alias = vim.treesitter.get_node_text(node, bufnr):lower() + metadata["injection.language"] = get_parser_from_markdown_info_string(injection_alias) +end, opts) + +-- Just avoid some annoying warnings for this directive +query.add_directive("make-range!", function() end, opts) + +--- transform node text to lower case (e.g., to make @injection.language case insensitive) +--- +---@param match (TSNode|nil)[] +---@param _ string +---@param bufnr integer +---@param pred string[] +---@return boolean|nil +query.add_directive("downcase!", function(match, _, bufnr, pred, metadata) + local id = pred[2] + local node = match[id] + if not node then + return + end + + local text = vim.treesitter.get_node_text(node, bufnr, { metadata = metadata[id] }) or "" + if not metadata[id] then + metadata[id] = {} + end + metadata[id].text = string.lower(text) +end, opts) + +-- Trim blank lines from end of the region +-- Arguments are the captures to trim. +---@param match (TSNode|nil)[] +---@param _ string +---@param bufnr integer +---@param pred string[] +---@param metadata table +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, opts) diff --git a/lua/nvim-treesitter/shell_command_selectors.lua b/lua/nvim-treesitter/shell_command_selectors.lua new file mode 100644 index 000000000..48f610169 --- /dev/null +++ b/lua/nvim-treesitter/shell_command_selectors.lua @@ -0,0 +1,365 @@ +local fn = vim.fn +local utils = require "nvim-treesitter.utils" +local uv = vim.uv or vim.loop + +-- Convert path for cmd.exe on Windows. +-- This is needed when vim.opt.shellslash is in use. +---@param p string +---@return string +local function cmdpath(p) + if vim.opt.shellslash:get() then + local r = p:gsub("/", "\\") + return r + else + return p + end +end + +local M = {} + +-- Returns the mkdir command based on the OS +---@param directory string +---@param cwd string +---@param info_msg string +---@return table +function M.select_mkdir_cmd(directory, cwd, info_msg) + if fn.has "win32" == 1 then + return { + cmd = "cmd", + opts = { + args = { "/C", "mkdir", cmdpath(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 + +-- Returns the remove command based on the OS +---@param file string +---@param info_msg string +---@return table +function M.select_rm_file_cmd(file, info_msg) + if fn.has "win32" == 1 then + return { + cmd = "cmd", + opts = { + args = { "/C", "if", "exist", cmdpath(file), "del", cmdpath(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 + +---@param executables string[] +---@return string|nil +function M.select_executable(executables) + return vim.tbl_filter(function(c) ---@param c string + return c ~= vim.NIL and fn.executable(c) == 1 + end, executables)[1] +end + +-- Returns the compiler arguments based on the compiler and OS +---@param repo InstallInfo +---@param compiler string +---@return string[] +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", + "/utf-8", + "/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, + "-Os", + } + if fn.has "mac" == 1 then + table.insert(args, "-bundle") + else + table.insert(args, "-shared") + end + if + #vim.tbl_filter(function(file) ---@param file string + local ext = vim.fn.fnamemodify(file, ":e") + return ext == "cc" or ext == "cpp" or ext == "cxx" + end, repo.files) > 0 + then + table.insert(args, "-lstdc++") + end + if fn.has "win32" == 0 then + table.insert(args, "-fPIC") + end + return args + end +end + +-- Returns the compile command based on the OS and user options +---@param repo InstallInfo +---@param cc string +---@param compile_location string +---@return Command +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 = require("nvim-treesitter.compat").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 + +-- Returns the remove command based on the OS +---@param cache_folder string +---@param project_name string +---@return Command +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", cmdpath(dir), "rmdir", "/s", "/q", cmdpath(dir) }, + }, + } + else + return { + cmd = "rm", + opts = { + args = { "-rf", cache_folder .. "/" .. project_name }, + }, + } + end +end + +-- Returns the move command based on the OS +---@param from string +---@param to string +---@param cwd string +---@return Command +function M.select_mv_cmd(from, to, cwd) + if fn.has "win32" == 1 then + return { + cmd = "cmd", + opts = { + args = { "/C", "move", "/Y", cmdpath(from), cmdpath(to) }, + cwd = cwd, + }, + } + else + return { + cmd = "mv", + opts = { + args = { "-f", from, to }, + cwd = cwd, + }, + } + end +end + +---@param repo InstallInfo +---@param project_name string +---@param cache_folder string +---@param revision string|nil +---@param prefer_git boolean +---@return table +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", + "--show-error", + "-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" + + -- Running `git clone` or `git checkout` while running under Git (such as + -- editing a `git commit` message) will likely fail to install parsers + -- (such as 'gitcommit') and can also corrupt the index file of the current + -- Git repository. Check for typical git environment variables and abort if found. + for _, k in pairs { + "GIT_ALTERNATE_OBJECT_DIRECTORIES", + "GIT_CEILING_DIRECTORIES", + "GIT_DIR", + "GIT_INDEX", + "GIT_INDEX_FILE", + "GIT_OBJECT_DIRECTORY", + "GIT_PREFIX", + "GIT_WORK_TREE", + } do + if uv.os_getenv(k) then + vim.api.nvim_err_writeln( + string.format( + "Cannot install %s with git in an active git session. Exit the session and run ':TSInstall %s' manually", + project_name, + project_name + ) + ) + return {} + end + end + + return { + { + cmd = "git", + info = "Downloading " .. project_name .. "...", + err = clone_error, + opts = { + args = { + "clone", + repo.url, + project_name, + "--filter=blob:none", + }, + 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 + +---@param dir string +---@param command string +---@return string command +function M.make_directory_change_for_command(dir, command) + if fn.has "win32" == 1 then + if string.find(vim.o.shell, "cmd") ~= nil then + return string.format("pushd %s & %s & popd", cmdpath(dir), command) + else + return string.format("pushd %s ; %s ; popd", cmdpath(dir), command) + end + 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..68ba41aca --- /dev/null +++ b/lua/nvim-treesitter/statusline.lua @@ -0,0 +1,53 @@ +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 allow_duplicates = options.allow_duplicates or false + + 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 ~= "" then + if allow_duplicates or not vim.tbl_contains(lines, line) then + table.insert(lines, 1, line) + end + 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..f2ee7f524 --- /dev/null +++ b/lua/nvim-treesitter/ts_utils.lua @@ -0,0 +1,468 @@ +local api = vim.api + +local parsers = require "nvim-treesitter.parsers" +local utils = require "nvim-treesitter.utils" +local ts = vim.treesitter + +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 = ts.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 +---@param node TSNode +---@param type_patterns string[] +---@param transform_fn fun(line: string): string +---@param bufnr integer +---@return string +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 ""), node) + -- 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.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.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 TSNode +---@param allow_switch_parents? boolean allow switching parents if last node +---@param allow_next_parent? boolean 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 ---@type TSNode + 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 TSNode +---@param allow_switch_parents? boolean allow switching parents if first node +---@param allow_previous_parent? boolean 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 ---@type TSNode + 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 = {} ---@type TSNode[] + 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 ---@type TSNode|nil + if ignore_injected_langs then + for _, tree in pairs(root_lang_tree:trees()) do + local tree_root = tree:root() + if tree_root and ts.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 pairs(lang_tree:trees()) do + local root = tree:root() + + if root and ts.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 + +---comment +---@param node TSNode +---@return TSNode result +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. +---comment +---@param range integer[] +---@param buf integer|nil +---@return integer, integer, integer, integer +function M.get_vim_range(range, buf) + ---@type integer, integer, integer, integer + 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 + ecol = math.max(ecol, 1) + end + return srow, scol, erow, ecol +end + +function M.highlight_range(range, buf, hl_namespace, hl_group) + ---@type integer, integer, integer, integer + local start_row, start_col, end_row, end_col = unpack(range) + ---@diagnostic disable-next-line: missing-parameter + 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) + local start_row, start_col, end_row, end_col = M.get_vim_range({ ts.get_node_range(node) }, buf) + + local v_table = { charwise = "v", linewise = "V", blockwise = "" } + selection_mode = selection_mode or "charwise" + + -- Normalise selection_mode + if vim.tbl_contains(vim.tbl_keys(v_table), selection_mode) then + selection_mode = v_table[selection_mode] + end + + -- enter visual mode if normal or operator-pending (no) mode + -- Why? According to https://learnvimscriptthehardway.stevelosh.com/chapters/15.html + -- If your operator-pending mapping ends with some text visually selected, Vim will operate on that text. + -- Otherwise, Vim will operate on the text between the original cursor position and the new position. + local mode = api.nvim_get_mode() + if mode.mode ~= selection_mode then + -- Call to `nvim_replace_termcodes()` is needed for sending appropriate command to enter blockwise mode + selection_mode = vim.api.nvim_replace_termcodes(selection_mode, true, true, true) + api.nvim_cmd({ cmd = "normal", bang = true, args = { selection_mode } }, {}) + end + + api.nvim_win_set_cursor(0, { start_row, start_col - 1 }) + vim.cmd "normal! o" + api.nvim_win_set_cursor(0, { end_row, end_col - 1 }) +end + +-- Byte length of node range +---@param node TSNode +---@return number +function M.node_length(node) + local _, _, start_byte = node:start() + local _, _, end_byte = node:end_() + return end_byte - start_byte +end + +---@deprecated Use `vim.treesitter.is_in_node_range()` instead +function M.is_in_node_range(node, line, col) + vim.notify_once( + "nvim-treesitter.ts_utils.is_in_node_range is deprecated: use vim.treesitter.is_in_node_range", + vim.log.levels.WARN + ) + return ts.is_in_node_range(node, line, col) +end + +---@deprecated Use `vim.treesitter.get_node_range()` instead +function M.get_node_range(node_or_range) + vim.notify_once( + "nvim-treesitter.ts_utils.get_node_range is deprecated: use vim.treesitter.get_node_range", + vim.log.levels.WARN + ) + return ts.get_node_range(node_or_range) +end + +---@param node TSNode +---@return table +function M.node_to_lsp_range(node) + local start_line, start_col, end_line, end_col = ts.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. +-- The options argument is a table with two optional values: +-- - bufnr: extracts a bufnr from the given arguments. +-- - key: extracts the cache key from the given arguments. +---@param fn function the fn to memoize, taking the buffer as first argument +---@param options? {bufnr: integer?, key: string|fun(...): string?} the memoization options +---@return function: a memoized function +function M.memoize_by_buf_tick(fn, options) + options = options or {} + + ---@type table + local cache = setmetatable({}, { __mode = "kv" }) + 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") } + bufnr = bufnr == 0 and vim.api.nvim_get_current_buf() or bufnr + 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() } } + ---@type table + local position + if not goto_end then + position = { range[1], range[2] } + else + position = { range[3], range[4] } + end + + -- Enter visual mode if we are in operator pending mode + -- If we don't do this, it will miss the last character. + local mode = vim.api.nvim_get_mode() + if mode.mode == "no" then + vim.cmd "normal! v" + 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..d920f4a61 --- /dev/null +++ b/lua/nvim-treesitter/utils.lua @@ -0,0 +1,237 @@ +local api = vim.api +local fn = vim.fn +local luv = vim.loop + +local M = {} + +-- Wrapper around vim.notify with common options set. +---@param msg string +---@param log_level number|nil +---@param opts table|nil +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 separator. +---@return string +function M.get_path_sep() + return (fn.has "win32" == 1 and not vim.opt.shellslash:get()) 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" +---@param separator string +---@return fun(...: string): string +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 " " + +---@class Command +---@field run function +---@field f_args string +---@field args string + +-- 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 hierarchy - 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 = require("nvim-treesitter.compat").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 table the table to access +---@param path string the '.' separated path +---@return table|nil result 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) + ---@type table[]|table + local result = tbl + + for _, segment in ipairs(segments) do + if type(result) == "table" then + ---@type table + -- TODO: figure out the actual type of tbl + result = result[segment] + end + end + + return result +end + +function M.set_jump() + vim.cmd "normal! m'" +end + +-- Filters a list based on the given predicate +---@param tbl any[] The list to filter +---@param predicate fun(v:any, i:number):boolean 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. +---@param tbl1 any[] The first table +---@param tbl2 any[] The second table +---@return 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 + +-- Returns a function returning the given value +---@param a any +---@return fun():any +function M.constant(a) + return function() + return a + end +end + +-- Returns a function that returns the given value if it is a function, +-- otherwise returns a function that returns the given value. +---@param a any +---@return fun(...):any +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" + if not handle then + return + end + 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/runtime/queries/ada/folds.scm b/queries/ada/folds.scm similarity index 100% rename from runtime/queries/ada/folds.scm rename to queries/ada/folds.scm diff --git a/runtime/queries/ada/highlights.scm b/queries/ada/highlights.scm similarity index 100% rename from runtime/queries/ada/highlights.scm rename to queries/ada/highlights.scm diff --git a/runtime/queries/ada/injections.scm b/queries/ada/injections.scm similarity index 100% rename from runtime/queries/ada/injections.scm rename to queries/ada/injections.scm diff --git a/runtime/queries/ada/locals.scm b/queries/ada/locals.scm similarity index 100% rename from runtime/queries/ada/locals.scm rename to queries/ada/locals.scm diff --git a/runtime/queries/agda/folds.scm b/queries/agda/folds.scm similarity index 100% rename from runtime/queries/agda/folds.scm rename to queries/agda/folds.scm diff --git a/runtime/queries/agda/highlights.scm b/queries/agda/highlights.scm similarity index 100% rename from runtime/queries/agda/highlights.scm rename to queries/agda/highlights.scm diff --git a/runtime/queries/agda/injections.scm b/queries/agda/injections.scm similarity index 100% rename from runtime/queries/agda/injections.scm rename to queries/agda/injections.scm diff --git a/runtime/queries/angular/folds.scm b/queries/angular/folds.scm similarity index 100% rename from runtime/queries/angular/folds.scm rename to queries/angular/folds.scm diff --git a/runtime/queries/angular/highlights.scm b/queries/angular/highlights.scm similarity index 91% rename from runtime/queries/angular/highlights.scm rename to queries/angular/highlights.scm index d248d2e4c..3783933f8 100644 --- a/runtime/queries/angular/highlights.scm +++ b/queries/angular/highlights.scm @@ -2,11 +2,12 @@ (identifier) @variable -(style_unit) @variable - (pipe_operator) @operator -(string) @string +[ + (string) + (static_member_expression) +] @string (number) @number @@ -28,12 +29,6 @@ (binding_name (identifier) @keyword) -(class_binding - [ - (identifier) - (class_name) - ] @keyword) - (event_binding (binding_name (identifier) @keyword)) @@ -113,14 +108,6 @@ "}}" ] @punctuation.special -(template_substitution - [ - "${" - "}" - ] @punctuation.special) - -(template_chars) @string - [ ";" "." diff --git a/runtime/queries/angular/indents.scm b/queries/angular/indents.scm similarity index 100% rename from runtime/queries/angular/indents.scm rename to queries/angular/indents.scm diff --git a/runtime/queries/angular/injections.scm b/queries/angular/injections.scm similarity index 100% rename from runtime/queries/angular/injections.scm rename to queries/angular/injections.scm diff --git a/runtime/queries/angular/locals.scm b/queries/angular/locals.scm similarity index 100% rename from runtime/queries/angular/locals.scm rename to queries/angular/locals.scm diff --git a/runtime/queries/apex/folds.scm b/queries/apex/folds.scm similarity index 100% rename from runtime/queries/apex/folds.scm rename to queries/apex/folds.scm diff --git a/runtime/queries/apex/highlights.scm b/queries/apex/highlights.scm similarity index 100% rename from runtime/queries/apex/highlights.scm rename to queries/apex/highlights.scm diff --git a/runtime/queries/asm/injections.scm b/queries/apex/injections.scm similarity index 100% rename from runtime/queries/asm/injections.scm rename to queries/apex/injections.scm diff --git a/runtime/queries/apex/locals.scm b/queries/apex/locals.scm similarity index 95% rename from runtime/queries/apex/locals.scm rename to queries/apex/locals.scm index d758f14cf..2457752fa 100644 --- a/runtime/queries/apex/locals.scm +++ b/queries/apex/locals.scm @@ -57,6 +57,9 @@ (formal_parameter name: (identifier) @local.definition.parameter) +(catch_formal_parameter + name: (identifier) @local.definition.parameter) + (field_declaration declarator: (variable_declarator name: (identifier) @local.definition.field)) 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/runtime/queries/arduino/highlights.scm b/queries/arduino/highlights.scm similarity index 100% rename from runtime/queries/arduino/highlights.scm rename to queries/arduino/highlights.scm 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..b637d9b2b --- /dev/null +++ b/queries/arduino/injections.scm @@ -0,0 +1,5 @@ +((preproc_arg) @injection.content + (#set! injection.language "arduino")) + +((comment) @injection.content + (#set! injection.language "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/asm/highlights.scm b/queries/asm/highlights.scm similarity index 100% rename from runtime/queries/asm/highlights.scm rename to queries/asm/highlights.scm diff --git a/runtime/queries/c3/injections.scm b/queries/asm/injections.scm similarity index 100% rename from runtime/queries/c3/injections.scm rename to queries/asm/injections.scm diff --git a/runtime/queries/astro/folds.scm b/queries/astro/folds.scm similarity index 100% rename from runtime/queries/astro/folds.scm rename to queries/astro/folds.scm diff --git a/runtime/queries/astro/highlights.scm b/queries/astro/highlights.scm similarity index 84% rename from runtime/queries/astro/highlights.scm rename to queries/astro/highlights.scm index e2917ad4d..e4baf5380 100644 --- a/runtime/queries/astro/highlights.scm +++ b/queries/astro/highlights.scm @@ -20,10 +20,6 @@ (tag_name) @type) (#lua-match? @type "^[A-Z]")) -((self_closing_tag - (tag_name) @type) - (#lua-match? @type "^[A-Z]")) - ((erroneous_end_tag (erroneous_end_tag_name) @type) (#lua-match? @type "^[A-Z]")) 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/runtime/queries/astro/injections.scm b/queries/astro/injections.scm similarity index 100% rename from runtime/queries/astro/injections.scm rename to queries/astro/injections.scm diff --git a/runtime/queries/astro/locals.scm b/queries/astro/locals.scm similarity index 100% rename from runtime/queries/astro/locals.scm rename to queries/astro/locals.scm diff --git a/runtime/queries/authzed/highlights.scm b/queries/authzed/highlights.scm similarity index 100% rename from runtime/queries/authzed/highlights.scm rename to queries/authzed/highlights.scm diff --git a/runtime/queries/authzed/injections.scm b/queries/authzed/injections.scm similarity index 100% rename from runtime/queries/authzed/injections.scm rename to queries/authzed/injections.scm diff --git a/runtime/queries/awk/highlights.scm b/queries/awk/highlights.scm similarity index 87% rename from runtime/queries/awk/highlights.scm rename to queries/awk/highlights.scm index 51ec9c08e..904cf2a9a 100644 --- a/runtime/queries/awk/highlights.scm +++ b/queries/awk/highlights.scm @@ -53,40 +53,6 @@ (identifier) @variable.parameter)) [ - "asort" - "asorti" - "bindtextdomain" - "compl" - "cos" - "dcgettext" - "dcngettext" - "exp" - "gensub" - "gsub" - "index" - "int" - "isarray" - "length" - "log" - "lshift" - "match" - "mktime" - "patsplit" - "rand" - "rshift" - "sin" - "split" - "sprintf" - "sqrt" - "srand" - "strftime" - "strtonum" - "sub" - "substr" - "systime" - "tolower" - "toupper" - "typeof" "print" "printf" "getline" diff --git a/runtime/queries/awk/injections.scm b/queries/awk/injections.scm similarity index 100% rename from runtime/queries/awk/injections.scm rename to queries/awk/injections.scm diff --git a/runtime/queries/bash/folds.scm b/queries/bash/folds.scm similarity index 100% rename from runtime/queries/bash/folds.scm rename to queries/bash/folds.scm diff --git a/runtime/queries/bash/highlights.scm b/queries/bash/highlights.scm similarity index 56% rename from runtime/queries/bash/highlights.scm rename to queries/bash/highlights.scm index 69bfaad1a..0e192bbcd 100644 --- a/runtime/queries/bash/highlights.scm +++ b/queries/bash/highlights.scm @@ -105,6 +105,21 @@ (special_variable_name) @constant +; trap -l +((word) @constant.builtin + (#any-of? @constant.builtin + "SIGHUP" "SIGINT" "SIGQUIT" "SIGILL" "SIGTRAP" "SIGABRT" "SIGBUS" "SIGFPE" "SIGKILL" "SIGUSR1" + "SIGSEGV" "SIGUSR2" "SIGPIPE" "SIGALRM" "SIGTERM" "SIGSTKFLT" "SIGCHLD" "SIGCONT" "SIGSTOP" + "SIGTSTP" "SIGTTIN" "SIGTTOU" "SIGURG" "SIGXCPU" "SIGXFSZ" "SIGVTALRM" "SIGPROF" "SIGWINCH" + "SIGIO" "SIGPWR" "SIGSYS" "SIGRTMIN" "SIGRTMIN+1" "SIGRTMIN+2" "SIGRTMIN+3" "SIGRTMIN+4" + "SIGRTMIN+5" "SIGRTMIN+6" "SIGRTMIN+7" "SIGRTMIN+8" "SIGRTMIN+9" "SIGRTMIN+10" "SIGRTMIN+11" + "SIGRTMIN+12" "SIGRTMIN+13" "SIGRTMIN+14" "SIGRTMIN+15" "SIGRTMAX-14" "SIGRTMAX-13" + "SIGRTMAX-12" "SIGRTMAX-11" "SIGRTMAX-10" "SIGRTMAX-9" "SIGRTMAX-8" "SIGRTMAX-7" "SIGRTMAX-6" + "SIGRTMAX-5" "SIGRTMAX-4" "SIGRTMAX-3" "SIGRTMAX-2" "SIGRTMAX-1" "SIGRTMAX")) + +((word) @boolean + (#any-of? @boolean "true" "false")) + (comment) @comment @spell (test_operator) @operator @@ -154,11 +169,11 @@ (command_name (word) @function.builtin (#any-of? @function.builtin - "." ":" "alias" "bg" "bind" "break" "builtin" "caller" "cd" "command" "compgen" "complete" - "compopt" "continue" "coproc" "dirs" "disown" "echo" "enable" "eval" "exec" "exit" "false" "fc" - "fg" "getopts" "hash" "help" "history" "jobs" "kill" "let" "logout" "mapfile" "popd" "printf" - "pushd" "pwd" "read" "readarray" "return" "set" "shift" "shopt" "source" "suspend" "test" "time" - "times" "trap" "true" "type" "typeset" "ulimit" "umask" "unalias" "wait")) + "alias" "bg" "bind" "break" "builtin" "caller" "cd" "command" "compgen" "complete" "compopt" + "continue" "coproc" "dirs" "disown" "echo" "enable" "eval" "exec" "exit" "fc" "fg" "getopts" + "hash" "help" "history" "jobs" "kill" "let" "logout" "mapfile" "popd" "printf" "pushd" "pwd" + "read" "readarray" "return" "set" "shift" "shopt" "source" "suspend" "test" "time" "times" + "trap" "type" "typeset" "ulimit" "umask" "unalias" "wait")) (command argument: [ @@ -167,30 +182,6 @@ (word) @variable.parameter) ]) -; help trap -(command - name: (command_name - (word) @_command) - argument: (word) @string.special - (#eq? @_command "trap") - (#any-of? @string.special "EXIT" "DEBUG" "RETURN" "ERR")) - -; trap -l -(command - name: (command_name - (word) @_command) - argument: (word) @string.special - (#any-of? @_command "trap" "kill") - (#any-of? @string.special - "SIGHUP" "SIGINT" "SIGQUIT" "SIGILL" "SIGTRAP" "SIGABRT" "SIGBUS" "SIGFPE" "SIGKILL" "SIGUSR1" - "SIGSEGV" "SIGUSR2" "SIGPIPE" "SIGALRM" "SIGTERM" "SIGSTKFLT" "SIGCHLD" "SIGCONT" "SIGSTOP" - "SIGTSTP" "SIGTTIN" "SIGTTOU" "SIGURG" "SIGXCPU" "SIGXFSZ" "SIGVTALRM" "SIGPROF" "SIGWINCH" - "SIGIO" "SIGPWR" "SIGSYS" "SIGRTMIN" "SIGRTMIN+1" "SIGRTMIN+2" "SIGRTMIN+3" "SIGRTMIN+4" - "SIGRTMIN+5" "SIGRTMIN+6" "SIGRTMIN+7" "SIGRTMIN+8" "SIGRTMIN+9" "SIGRTMIN+10" "SIGRTMIN+11" - "SIGRTMIN+12" "SIGRTMIN+13" "SIGRTMIN+14" "SIGRTMIN+15" "SIGRTMAX-14" "SIGRTMAX-13" - "SIGRTMAX-12" "SIGRTMAX-11" "SIGRTMAX-10" "SIGRTMAX-9" "SIGRTMAX-8" "SIGRTMAX-7" "SIGRTMAX-6" - "SIGRTMAX-5" "SIGRTMAX-4" "SIGRTMAX-3" "SIGRTMAX-2" "SIGRTMAX-1" "SIGRTMAX")) - (declaration_command (word) @variable.parameter) @@ -199,11 +190,11 @@ (number) @number -(file_redirect - (word) @string.special.path) +((word) @number + (#lua-match? @number "^[0-9]+$")) -(herestring_redirect - (word) @string) +(file_redirect + destination: (word) @variable.parameter) (file_descriptor) @operator @@ -234,36 +225,6 @@ ((variable_name) @constant (#lua-match? @constant "^[A-Z][A-Z_0-9]*$")) -((variable_name) @variable.builtin - (#any-of? @variable.builtin - ; https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Variables.html - "CDPATH" "HOME" "IFS" "MAIL" "MAILPATH" "OPTARG" "OPTIND" "PATH" "PS1" "PS2" - ; https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html - "_" "BASH" "BASHOPTS" "BASHPID" "BASH_ALIASES" "BASH_ARGC" "BASH_ARGV" "BASH_ARGV0" "BASH_CMDS" - "BASH_COMMAND" "BASH_COMPAT" "BASH_ENV" "BASH_EXECUTION_STRING" "BASH_LINENO" - "BASH_LOADABLES_PATH" "BASH_REMATCH" "BASH_SOURCE" "BASH_SUBSHELL" "BASH_VERSINFO" - "BASH_VERSION" "BASH_XTRACEFD" "CHILD_MAX" "COLUMNS" "COMP_CWORD" "COMP_LINE" "COMP_POINT" - "COMP_TYPE" "COMP_KEY" "COMP_WORDBREAKS" "COMP_WORDS" "COMPREPLY" "COPROC" "DIRSTACK" "EMACS" - "ENV" "EPOCHREALTIME" "EPOCHSECONDS" "EUID" "EXECIGNORE" "FCEDIT" "FIGNORE" "FUNCNAME" - "FUNCNEST" "GLOBIGNORE" "GROUPS" "histchars" "HISTCMD" "HISTCONTROL" "HISTFILE" "HISTFILESIZE" - "HISTIGNORE" "HISTSIZE" "HISTTIMEFORMAT" "HOSTFILE" "HOSTNAME" "HOSTTYPE" "IGNOREEOF" "INPUTRC" - "INSIDE_EMACS" "LANG" "LC_ALL" "LC_COLLATE" "LC_CTYPE" "LC_MESSAGES" "LC_NUMERIC" "LC_TIME" - "LINENO" "LINES" "MACHTYPE" "MAILCHECK" "MAPFILE" "OLDPWD" "OPTERR" "OSTYPE" "PIPESTATUS" - "POSIXLY_CORRECT" "PPID" "PROMPT_COMMAND" "PROMPT_DIRTRIM" "PS0" "PS3" "PS4" "PWD" "RANDOM" - "READLINE_ARGUMENT" "READLINE_LINE" "READLINE_MARK" "READLINE_POINT" "REPLY" "SECONDS" "SHELL" - "SHELLOPTS" "SHLVL" "SRANDOM" "TIMEFORMAT" "TMOUT" "TMPDIR" "UID")) - -((command - name: (command_name - (word) @_printf) - . - argument: (word) @_v - . - argument: (word) @variable) - (#eq? @_printf "printf") - (#eq? @_v "-v") - (#lua-match? @variable "^[a-zA-Z_][a-zA-Z0-9_]*$")) - (case_item value: (word) @variable.parameter) @@ -275,4 +236,4 @@ ((program . (comment) @keyword.directive @nospell) - (#lua-match? @keyword.directive "^#![ \t]*/")) + (#lua-match? @keyword.directive "^#!/")) diff --git a/runtime/queries/zsh/injections.scm b/queries/bash/injections.scm similarity index 73% rename from runtime/queries/zsh/injections.scm rename to queries/bash/injections.scm index 3e21206ab..328630808 100644 --- a/runtime/queries/zsh/injections.scm +++ b/queries/bash/injections.scm @@ -2,28 +2,28 @@ (#set! injection.language "comment")) ((regex) @injection.content - (#not-lua-match? @injection.content "%${.*}") (#set! injection.language "regex")) -(heredoc_redirect +((heredoc_redirect (heredoc_body) @injection.content (heredoc_end) @injection.language) + (#downcase! @injection.language)) ; printf 'format' ((command name: (command_name) @_command . argument: [ - (string) @injection.content + (string + (string_content) @injection.content) (concatenation - (string) @injection.content) + (string + (string_content) @injection.content)) (raw_string) @injection.content (concatenation (raw_string) @injection.content) ]) (#eq? @_command "printf") - (#offset! @injection.content 0 1 0 -1) - (#set! injection.include-children) (#set! injection.language "printf")) ; printf -v var 'format' @@ -34,17 +34,17 @@ (_) . argument: [ - (string) @injection.content + (string + (string_content) @injection.content) (concatenation - (string) @injection.content) + (string + (string_content) @injection.content)) (raw_string) @injection.content (concatenation (raw_string) @injection.content) ]) (#eq? @_command "printf") (#eq? @_arg "-v") - (#offset! @injection.content 0 1 0 -1) - (#set! injection.include-children) (#set! injection.language "printf")) ; printf -- 'format' @@ -53,17 +53,17 @@ argument: (word) @_arg . argument: [ - (string) @injection.content + (string + (string_content) @injection.content) (concatenation - (string) @injection.content) + (string + (string_content) @injection.content)) (raw_string) @injection.content (concatenation (raw_string) @injection.content) ]) (#eq? @_command "printf") (#eq? @_arg "--") - (#offset! @injection.content 0 1 0 -1) - (#set! injection.include-children) (#set! injection.language "printf")) ((command diff --git a/runtime/queries/bash/locals.scm b/queries/bash/locals.scm similarity index 100% rename from runtime/queries/bash/locals.scm rename to queries/bash/locals.scm diff --git a/runtime/queries/bass/folds.scm b/queries/bass/folds.scm similarity index 100% rename from runtime/queries/bass/folds.scm rename to queries/bass/folds.scm diff --git a/runtime/queries/bass/highlights.scm b/queries/bass/highlights.scm similarity index 98% rename from runtime/queries/bass/highlights.scm rename to queries/bass/highlights.scm index 8508de9ab..f84993af1 100644 --- a/runtime/queries/bass/highlights.scm +++ b/queries/bass/highlights.scm @@ -79,7 +79,7 @@ ; Repeats ((symbol) @keyword.repeat - (#eq? @keyword.repeat "each")) + (#any-of? @keyword.repeat "each")) ; Operators ((symbol) @operator diff --git a/runtime/queries/bass/indents.scm b/queries/bass/indents.scm similarity index 100% rename from runtime/queries/bass/indents.scm rename to queries/bass/indents.scm diff --git a/runtime/queries/bass/injections.scm b/queries/bass/injections.scm similarity index 100% rename from runtime/queries/bass/injections.scm rename to queries/bass/injections.scm diff --git a/runtime/queries/bass/locals.scm b/queries/bass/locals.scm similarity index 100% rename from runtime/queries/bass/locals.scm rename to queries/bass/locals.scm diff --git a/runtime/queries/beancount/folds.scm b/queries/beancount/folds.scm similarity index 100% rename from runtime/queries/beancount/folds.scm rename to queries/beancount/folds.scm diff --git a/runtime/queries/beancount/highlights.scm b/queries/beancount/highlights.scm similarity index 100% rename from runtime/queries/beancount/highlights.scm rename to queries/beancount/highlights.scm diff --git a/runtime/queries/beancount/injections.scm b/queries/beancount/injections.scm similarity index 100% rename from runtime/queries/beancount/injections.scm rename to queries/beancount/injections.scm diff --git a/runtime/queries/bibtex/folds.scm b/queries/bibtex/folds.scm similarity index 100% rename from runtime/queries/bibtex/folds.scm rename to queries/bibtex/folds.scm diff --git a/runtime/queries/bibtex/highlights.scm b/queries/bibtex/highlights.scm similarity index 73% rename from runtime/queries/bibtex/highlights.scm rename to queries/bibtex/highlights.scm index 2231a17db..a82b371ae 100644 --- a/runtime/queries/bibtex/highlights.scm +++ b/queries/bibtex/highlights.scm @@ -22,7 +22,7 @@ (number) @number (field - name: (identifier) @property) + name: (identifier) @variable.member) (token (identifier) @variable.parameter) @@ -32,17 +32,10 @@ (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 +] @string.special.symbol (string name: (identifier) @constant) diff --git a/runtime/queries/bibtex/indents.scm b/queries/bibtex/indents.scm similarity index 100% rename from runtime/queries/bibtex/indents.scm rename to queries/bibtex/indents.scm diff --git a/runtime/queries/bibtex/injections.scm b/queries/bibtex/injections.scm similarity index 100% rename from runtime/queries/bibtex/injections.scm rename to queries/bibtex/injections.scm diff --git a/runtime/queries/bicep/folds.scm b/queries/bicep/folds.scm similarity index 100% rename from runtime/queries/bicep/folds.scm rename to queries/bicep/folds.scm diff --git a/runtime/queries/bicep/highlights.scm b/queries/bicep/highlights.scm similarity index 100% rename from runtime/queries/bicep/highlights.scm rename to queries/bicep/highlights.scm diff --git a/runtime/queries/bicep/indents.scm b/queries/bicep/indents.scm similarity index 100% rename from runtime/queries/bicep/indents.scm rename to queries/bicep/indents.scm diff --git a/runtime/queries/bicep/injections.scm b/queries/bicep/injections.scm similarity index 100% rename from runtime/queries/bicep/injections.scm rename to queries/bicep/injections.scm diff --git a/runtime/queries/bicep/locals.scm b/queries/bicep/locals.scm similarity index 100% rename from runtime/queries/bicep/locals.scm rename to queries/bicep/locals.scm diff --git a/runtime/queries/bitbake/folds.scm b/queries/bitbake/folds.scm similarity index 100% rename from runtime/queries/bitbake/folds.scm rename to queries/bitbake/folds.scm diff --git a/runtime/queries/bitbake/highlights.scm b/queries/bitbake/highlights.scm similarity index 99% rename from runtime/queries/bitbake/highlights.scm rename to queries/bitbake/highlights.scm index e10ae705b..c7316de6e 100644 --- a/runtime/queries/bitbake/highlights.scm +++ b/queries/bitbake/highlights.scm @@ -281,6 +281,7 @@ "=." "-" "-=" + ":=" "!=" "*" "**" diff --git a/runtime/queries/bitbake/indents.scm b/queries/bitbake/indents.scm similarity index 100% rename from runtime/queries/bitbake/indents.scm rename to queries/bitbake/indents.scm diff --git a/runtime/queries/bitbake/injections.scm b/queries/bitbake/injections.scm similarity index 100% rename from runtime/queries/bitbake/injections.scm rename to queries/bitbake/injections.scm diff --git a/runtime/queries/bitbake/locals.scm b/queries/bitbake/locals.scm similarity index 100% rename from runtime/queries/bitbake/locals.scm rename to queries/bitbake/locals.scm diff --git a/queries/blueprint/highlights.scm b/queries/blueprint/highlights.scm new file mode 100644 index 000000000..f3c39f232 --- /dev/null +++ b/queries/blueprint/highlights.scm @@ -0,0 +1,75 @@ +(object_id) @variable + +(string) @string + +(escape_sequence) @string.escape + +(comment) @comment @spell + +(constant) @constant.builtin + +(boolean) @boolean + +(using) @keyword.import + +(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) + +(import_statement + (gobject_library) @module) + +(import_statement + (version_number) @number.float) + +(float) @number.float + +(number) @number + +[ + ";" + "." + "," +] @punctuation.delimiter + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket diff --git a/runtime/queries/bp/injections.scm b/queries/blueprint/injections.scm similarity index 100% rename from runtime/queries/bp/injections.scm rename to queries/blueprint/injections.scm diff --git a/runtime/queries/bp/folds.scm b/queries/bp/folds.scm similarity index 100% rename from runtime/queries/bp/folds.scm rename to queries/bp/folds.scm diff --git a/runtime/queries/bp/highlights.scm b/queries/bp/highlights.scm similarity index 100% rename from runtime/queries/bp/highlights.scm rename to queries/bp/highlights.scm diff --git a/runtime/queries/bp/indents.scm b/queries/bp/indents.scm similarity index 100% rename from runtime/queries/bp/indents.scm rename to queries/bp/indents.scm diff --git a/runtime/queries/brightscript/injections.scm b/queries/bp/injections.scm similarity index 100% rename from runtime/queries/brightscript/injections.scm rename to queries/bp/injections.scm diff --git a/runtime/queries/bp/locals.scm b/queries/bp/locals.scm similarity index 100% rename from runtime/queries/bp/locals.scm rename to queries/bp/locals.scm diff --git a/runtime/queries/c/folds.scm b/queries/c/folds.scm similarity index 100% rename from runtime/queries/c/folds.scm rename to queries/c/folds.scm diff --git a/runtime/queries/c/highlights.scm b/queries/c/highlights.scm similarity index 98% rename from runtime/queries/c/highlights.scm rename to queries/c/highlights.scm index 442343abf..bd6857fd1 100644 --- a/runtime/queries/c/highlights.scm +++ b/queries/c/highlights.scm @@ -65,7 +65,6 @@ ";" ":" "," - "." "::" ] @punctuation.delimiter @@ -94,6 +93,7 @@ "<<" ">>" "->" + "." "<" "<=" ">=" @@ -149,7 +149,7 @@ ((field_expression (field_identifier) @property) @_parent - (#not-has-parent? @_parent function_declarator call_expression)) + (#not-has-parent? @_parent template_method function_declarator call_expression)) (field_designator) @property diff --git a/runtime/queries/c/indents.scm b/queries/c/indents.scm similarity index 100% rename from runtime/queries/c/indents.scm rename to queries/c/indents.scm diff --git a/runtime/queries/c/injections.scm b/queries/c/injections.scm similarity index 96% rename from runtime/queries/c/injections.scm rename to queries/c/injections.scm index ebedc1ec3..77b4d7a86 100644 --- a/runtime/queries/c/injections.scm +++ b/queries/c/injections.scm @@ -1,5 +1,5 @@ ((preproc_arg) @injection.content - (#set! injection.self)) + (#set! injection.language "c")) ((comment) @injection.content (#set! injection.language "comment")) @@ -9,7 +9,7 @@ (#set! injection.language "re2c")) ((comment) @injection.content - (#lua-match? @injection.content "/[*/][!*/]" - ] @punctuation.bracket) - (type_argument_list [ "<" diff --git a/runtime/queries/c_sharp/injections.scm b/queries/c_sharp/injections.scm similarity index 100% rename from runtime/queries/c_sharp/injections.scm rename to queries/c_sharp/injections.scm diff --git a/runtime/queries/c_sharp/locals.scm b/queries/c_sharp/locals.scm similarity index 100% rename from runtime/queries/c_sharp/locals.scm rename to queries/c_sharp/locals.scm diff --git a/runtime/queries/cairo/folds.scm b/queries/cairo/folds.scm similarity index 100% rename from runtime/queries/cairo/folds.scm rename to queries/cairo/folds.scm diff --git a/runtime/queries/cairo/highlights.scm b/queries/cairo/highlights.scm similarity index 100% rename from runtime/queries/cairo/highlights.scm rename to queries/cairo/highlights.scm diff --git a/runtime/queries/cairo/indents.scm b/queries/cairo/indents.scm similarity index 100% rename from runtime/queries/cairo/indents.scm rename to queries/cairo/indents.scm diff --git a/runtime/queries/cairo/injections.scm b/queries/cairo/injections.scm similarity index 100% rename from runtime/queries/cairo/injections.scm rename to queries/cairo/injections.scm diff --git a/runtime/queries/cairo/locals.scm b/queries/cairo/locals.scm similarity index 100% rename from runtime/queries/cairo/locals.scm rename to queries/cairo/locals.scm diff --git a/runtime/queries/capnp/folds.scm b/queries/capnp/folds.scm similarity index 100% rename from runtime/queries/capnp/folds.scm rename to queries/capnp/folds.scm diff --git a/runtime/queries/capnp/highlights.scm b/queries/capnp/highlights.scm similarity index 100% rename from runtime/queries/capnp/highlights.scm rename to queries/capnp/highlights.scm diff --git a/runtime/queries/capnp/indents.scm b/queries/capnp/indents.scm similarity index 100% rename from runtime/queries/capnp/indents.scm rename to queries/capnp/indents.scm diff --git a/runtime/queries/caddy/injections.scm b/queries/capnp/injections.scm similarity index 100% rename from runtime/queries/caddy/injections.scm rename to queries/capnp/injections.scm diff --git a/runtime/queries/capnp/locals.scm b/queries/capnp/locals.scm similarity index 100% rename from runtime/queries/capnp/locals.scm rename to queries/capnp/locals.scm diff --git a/runtime/queries/chatito/folds.scm b/queries/chatito/folds.scm similarity index 100% rename from runtime/queries/chatito/folds.scm rename to queries/chatito/folds.scm diff --git a/runtime/queries/chatito/highlights.scm b/queries/chatito/highlights.scm similarity index 97% rename from runtime/queries/chatito/highlights.scm rename to queries/chatito/highlights.scm index e756064b3..47113f2cf 100644 --- a/runtime/queries/chatito/highlights.scm +++ b/queries/chatito/highlights.scm @@ -11,7 +11,7 @@ "," @punctuation.delimiter -eq: _ @operator +(eq) @operator ([ "\"" diff --git a/runtime/queries/chatito/indents.scm b/queries/chatito/indents.scm similarity index 100% rename from runtime/queries/chatito/indents.scm rename to queries/chatito/indents.scm diff --git a/runtime/queries/capnp/injections.scm b/queries/chatito/injections.scm similarity index 100% rename from runtime/queries/capnp/injections.scm rename to queries/chatito/injections.scm diff --git a/runtime/queries/chatito/locals.scm b/queries/chatito/locals.scm similarity index 100% rename from runtime/queries/chatito/locals.scm rename to queries/chatito/locals.scm diff --git a/runtime/queries/clojure/folds.scm b/queries/clojure/folds.scm similarity index 100% rename from runtime/queries/clojure/folds.scm rename to queries/clojure/folds.scm diff --git a/runtime/queries/clojure/highlights.scm b/queries/clojure/highlights.scm similarity index 100% rename from runtime/queries/clojure/highlights.scm rename to queries/clojure/highlights.scm diff --git a/runtime/queries/chatito/injections.scm b/queries/clojure/injections.scm similarity index 100% rename from runtime/queries/chatito/injections.scm rename to queries/clojure/injections.scm 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/runtime/queries/cmake/folds.scm b/queries/cmake/folds.scm similarity index 100% rename from runtime/queries/cmake/folds.scm rename to queries/cmake/folds.scm diff --git a/runtime/queries/cmake/highlights.scm b/queries/cmake/highlights.scm similarity index 99% rename from runtime/queries/cmake/highlights.scm rename to queries/cmake/highlights.scm index 41713ea16..fbbf0d542 100644 --- a/runtime/queries/cmake/highlights.scm +++ b/queries/cmake/highlights.scm @@ -137,7 +137,7 @@ ((argument) @_cache @keyword.modifier . (argument) @_type @type - (#eq? @_cache "CACHE") + (#any-of? @_cache "CACHE") (#any-of? @_type "BOOL" "FILEPATH" "PATH" "STRING" "INTERNAL")))) (normal_command diff --git a/runtime/queries/cmake/indents.scm b/queries/cmake/indents.scm similarity index 100% rename from runtime/queries/cmake/indents.scm rename to queries/cmake/indents.scm diff --git a/runtime/queries/cmake/injections.scm b/queries/cmake/injections.scm similarity index 100% rename from runtime/queries/cmake/injections.scm rename to queries/cmake/injections.scm diff --git a/runtime/queries/comment/highlights.scm b/queries/comment/highlights.scm similarity index 100% rename from runtime/queries/comment/highlights.scm rename to queries/comment/highlights.scm diff --git a/runtime/queries/commonlisp/folds.scm b/queries/commonlisp/folds.scm similarity index 100% rename from runtime/queries/commonlisp/folds.scm rename to queries/commonlisp/folds.scm diff --git a/runtime/queries/commonlisp/highlights.scm b/queries/commonlisp/highlights.scm similarity index 99% rename from runtime/queries/commonlisp/highlights.scm rename to queries/commonlisp/highlights.scm index dbd41657f..7236c84de 100644 --- a/runtime/queries/commonlisp/highlights.scm +++ b/queries/commonlisp/highlights.scm @@ -295,7 +295,8 @@ "clear-output" "assoc-if" "string/=" "princ" "directory-namestring" "stream-error-stream" "array-element-type" "setq" "copy-seq" "time" "restart-case" "prog*" "shared-initialize" "array-total-size" "simple-bit-vector-p" "define-method-combination" "write-byte" "constantly" - "caddar" "print-object" "vector" "throw" "reverse" ">=" "upper-case-p" "nbutlast")) + "caddar" "print-object" "vector" "throw" "reverse" ">=" "upper-case-p" "nbutlast") + ) (list_lit . diff --git a/runtime/queries/commonlisp/injections.scm b/queries/commonlisp/injections.scm similarity index 100% rename from runtime/queries/commonlisp/injections.scm rename to queries/commonlisp/injections.scm diff --git a/runtime/queries/commonlisp/locals.scm b/queries/commonlisp/locals.scm similarity index 100% rename from runtime/queries/commonlisp/locals.scm rename to queries/commonlisp/locals.scm diff --git a/runtime/queries/cooklang/highlights.scm b/queries/cooklang/highlights.scm similarity index 100% rename from runtime/queries/cooklang/highlights.scm rename to queries/cooklang/highlights.scm diff --git a/runtime/queries/circom/injections.scm b/queries/cooklang/injections.scm similarity index 100% rename from runtime/queries/circom/injections.scm rename to queries/cooklang/injections.scm diff --git a/runtime/queries/corn/folds.scm b/queries/corn/folds.scm similarity index 100% rename from runtime/queries/corn/folds.scm rename to queries/corn/folds.scm diff --git a/runtime/queries/corn/highlights.scm b/queries/corn/highlights.scm similarity index 100% rename from runtime/queries/corn/highlights.scm rename to queries/corn/highlights.scm diff --git a/runtime/queries/corn/indents.scm b/queries/corn/indents.scm similarity index 100% rename from runtime/queries/corn/indents.scm rename to queries/corn/indents.scm diff --git a/runtime/queries/clojure/injections.scm b/queries/corn/injections.scm similarity index 100% rename from runtime/queries/clojure/injections.scm rename to queries/corn/injections.scm diff --git a/runtime/queries/corn/locals.scm b/queries/corn/locals.scm similarity index 100% rename from runtime/queries/corn/locals.scm rename to queries/corn/locals.scm diff --git a/runtime/queries/cpon/folds.scm b/queries/cpon/folds.scm similarity index 100% rename from runtime/queries/cpon/folds.scm rename to queries/cpon/folds.scm diff --git a/runtime/queries/cpon/highlights.scm b/queries/cpon/highlights.scm similarity index 100% rename from runtime/queries/cpon/highlights.scm rename to queries/cpon/highlights.scm diff --git a/runtime/queries/cpon/indents.scm b/queries/cpon/indents.scm similarity index 100% rename from runtime/queries/cpon/indents.scm rename to queries/cpon/indents.scm diff --git a/runtime/queries/cooklang/injections.scm b/queries/cpon/injections.scm similarity index 100% rename from runtime/queries/cooklang/injections.scm rename to queries/cpon/injections.scm diff --git a/runtime/queries/cpon/locals.scm b/queries/cpon/locals.scm similarity index 100% rename from runtime/queries/cpon/locals.scm rename to queries/cpon/locals.scm diff --git a/runtime/queries/cpp/folds.scm b/queries/cpp/folds.scm similarity index 100% rename from runtime/queries/cpp/folds.scm rename to queries/cpp/folds.scm diff --git a/runtime/queries/cpp/highlights.scm b/queries/cpp/highlights.scm similarity index 97% rename from runtime/queries/cpp/highlights.scm rename to queries/cpp/highlights.scm index ac0315275..85ff2dc40 100644 --- a/runtime/queries/cpp/highlights.scm +++ b/queries/cpp/highlights.scm @@ -154,11 +154,6 @@ (field_expression (field_identifier) @function.method.call)) -(call_expression - (field_expression - (template_method - (field_identifier) @function.method.call))) - ; constructors ((function_declarator (qualified_identifier diff --git a/runtime/queries/cpp/indents.scm b/queries/cpp/indents.scm similarity index 100% rename from runtime/queries/cpp/indents.scm rename to queries/cpp/indents.scm diff --git a/queries/cpp/injections.scm b/queries/cpp/injections.scm new file mode 100644 index 000000000..6e1657229 --- /dev/null +++ b/queries/cpp/injections.scm @@ -0,0 +1,13 @@ +((preproc_arg) @injection.content + (#set! injection.language "cpp")) + +((comment) @injection.content + (#set! injection.language "comment")) + +((comment) @injection.content + (#lua-match? @injection.content "/[*\/][!*\/]|" + "&" + ".." + "!" + (direction) + (stream_redirect) +] @operator + +; match operators of test command +(command + name: (word) @function.builtin + (#eq? @function.builtin "test") + argument: (word) @operator + (#match? @operator "^(!?\\=|-[a-zA-Z]+)$")) + +; match operators of [ command +(command + name: (word) @punctuation.bracket + (#eq? @punctuation.bracket "[") + argument: (word) @operator + (#match? @operator "^(!?\\=|-[a-zA-Z]+)$")) + +[ + "not" + "and" + "or" +] @keyword.operator + +; Conditionals +(if_statement + [ + "if" + "end" + ] @keyword.conditional) + +(switch_statement + [ + "switch" + "end" + ] @keyword.conditional) + +(case_clause + "case" @keyword.conditional) + +(else_clause + "else" @keyword.conditional) + +(else_if_clause + [ + "else" + "if" + ] @keyword.conditional) + +; Loops/Blocks +(while_statement + [ + "while" + "end" + ] @keyword.repeat) + +(for_statement + [ + "for" + "end" + ] @keyword.repeat) + +(begin_statement + [ + "begin" + "end" + ] @keyword.repeat) + +; Keywords +[ + "in" + (break) + (continue) +] @keyword + +"return" @keyword.return + +; Punctuation +[ + "[" + "]" + "{" + "}" + "(" + ")" +] @punctuation.bracket + +"," @punctuation.delimiter + +; Commands +(command + argument: [ + (word) @variable.parameter + (#lua-match? @variable.parameter "^[-]") + ]) + +(command_substitution + "$" @punctuation.bracket) + +; non-builtin 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") + ]) + +; Functions +(function_definition + [ + "function" + "end" + ] @keyword.function) + +(function_definition + name: [ + (word) + (concatenation) + ] @function) + +(function_definition + option: [ + (word) + (concatenation + (word)) + ] @variable.parameter + (#lua-match? @variable.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) @keyword.directive @nospell) + (#lua-match? @keyword.directive "^#!/")) diff --git a/runtime/queries/fish/indents.scm b/queries/fish/indents.scm similarity index 100% rename from runtime/queries/fish/indents.scm rename to queries/fish/indents.scm diff --git a/runtime/queries/fidl/injections.scm b/queries/fish/injections.scm similarity index 100% rename from runtime/queries/fidl/injections.scm rename to queries/fish/injections.scm diff --git a/runtime/queries/fish/locals.scm b/queries/fish/locals.scm similarity index 100% rename from runtime/queries/fish/locals.scm rename to queries/fish/locals.scm diff --git a/runtime/queries/foam/folds.scm b/queries/foam/folds.scm similarity index 100% rename from runtime/queries/foam/folds.scm rename to queries/foam/folds.scm diff --git a/runtime/queries/foam/highlights.scm b/queries/foam/highlights.scm similarity index 100% rename from runtime/queries/foam/highlights.scm rename to queries/foam/highlights.scm diff --git a/runtime/queries/foam/indents.scm b/queries/foam/indents.scm similarity index 100% rename from runtime/queries/foam/indents.scm rename to queries/foam/indents.scm diff --git a/runtime/queries/foam/injections.scm b/queries/foam/injections.scm similarity index 100% rename from runtime/queries/foam/injections.scm rename to queries/foam/injections.scm diff --git a/runtime/queries/foam/locals.scm b/queries/foam/locals.scm similarity index 100% rename from runtime/queries/foam/locals.scm rename to queries/foam/locals.scm diff --git a/runtime/queries/forth/folds.scm b/queries/forth/folds.scm similarity index 100% rename from runtime/queries/forth/folds.scm rename to queries/forth/folds.scm diff --git a/runtime/queries/forth/highlights.scm b/queries/forth/highlights.scm similarity index 100% rename from runtime/queries/forth/highlights.scm rename to queries/forth/highlights.scm diff --git a/runtime/queries/forth/indents.scm b/queries/forth/indents.scm similarity index 100% rename from runtime/queries/forth/indents.scm rename to queries/forth/indents.scm diff --git a/runtime/queries/firrtl/injections.scm b/queries/forth/injections.scm similarity index 100% rename from runtime/queries/firrtl/injections.scm rename to queries/forth/injections.scm diff --git a/runtime/queries/forth/locals.scm b/queries/forth/locals.scm similarity index 100% rename from runtime/queries/forth/locals.scm rename to queries/forth/locals.scm diff --git a/runtime/queries/fortran/folds.scm b/queries/fortran/folds.scm similarity index 87% rename from runtime/queries/fortran/folds.scm rename to queries/fortran/folds.scm index 7b06b1719..cedbdb635 100644 --- a/runtime/queries/fortran/folds.scm +++ b/queries/fortran/folds.scm @@ -3,7 +3,7 @@ (if_statement) (where_statement) (enum_statement) - (do_loop) + (do_loop_statement) (derived_type_definition) (function) (subroutine) diff --git a/runtime/queries/fortran/highlights.scm b/queries/fortran/highlights.scm similarity index 100% rename from runtime/queries/fortran/highlights.scm rename to queries/fortran/highlights.scm diff --git a/runtime/queries/fortran/indents.scm b/queries/fortran/indents.scm similarity index 95% rename from runtime/queries/fortran/indents.scm rename to queries/fortran/indents.scm index 0f9ba3d7e..86704c4f4 100644 --- a/runtime/queries/fortran/indents.scm +++ b/queries/fortran/indents.scm @@ -5,7 +5,7 @@ (function) ; (interface) (if_statement) - (do_loop) + (do_loop_statement) (where_statement) (derived_type_definition) (enum) diff --git a/runtime/queries/fish/injections.scm b/queries/fortran/injections.scm similarity index 100% rename from runtime/queries/fish/injections.scm rename to queries/fortran/injections.scm diff --git a/runtime/queries/fsh/highlights.scm b/queries/fsh/highlights.scm similarity index 100% rename from runtime/queries/fsh/highlights.scm rename to queries/fsh/highlights.scm diff --git a/runtime/queries/fsh/injections.scm b/queries/fsh/injections.scm similarity index 100% rename from runtime/queries/fsh/injections.scm rename to queries/fsh/injections.scm diff --git a/runtime/queries/fsharp/highlights.scm b/queries/fsharp/highlights.scm similarity index 96% rename from runtime/queries/fsharp/highlights.scm rename to queries/fsharp/highlights.scm index ba70ea5c6..e400e3522 100644 --- a/runtime/queries/fsharp/highlights.scm +++ b/queries/fsharp/highlights.scm @@ -123,7 +123,7 @@ ((argument_patterns (long_identifier (identifier) @character.special)) - (#lua-match? @character.special "^_.*")) + (#lua-match? @character.special "^\_.*")) (member_defn (method_or_prop_defn @@ -246,6 +246,7 @@ "<-" "&" "&&" + "|" "||" ":>" ":?>" @@ -376,9 +377,8 @@ (unit) @function.call) ((_type - (simple_type - (long_identifier - (identifier) @type.builtin))) + (long_identifier + (identifier) @type.builtin)) (#any-of? @type.builtin "bool" "byte" "sbyte" "int16" "uint16" "int" "uint" "int64" "uint64" "nativeint" "unativeint" "decimal" "float" "double" "float32" "single" "char" "string" "unit")) @@ -402,9 +402,8 @@ (attributes (attribute (_type - (simple_type - (long_identifier - (identifier) @attribute))))) + (long_identifier + (identifier) @attribute)))) (function_or_value_defn (value_declaration_left . diff --git a/runtime/queries/fsharp/injections.scm b/queries/fsharp/injections.scm similarity index 100% rename from runtime/queries/fsharp/injections.scm rename to queries/fsharp/injections.scm diff --git a/runtime/queries/func/highlights.scm b/queries/func/highlights.scm similarity index 100% rename from runtime/queries/func/highlights.scm rename to queries/func/highlights.scm diff --git a/runtime/queries/forth/injections.scm b/queries/func/injections.scm similarity index 100% rename from runtime/queries/forth/injections.scm rename to queries/func/injections.scm diff --git a/queries/fusion/folds.scm b/queries/fusion/folds.scm new file mode 100644 index 000000000..179fc160b --- /dev/null +++ b/queries/fusion/folds.scm @@ -0,0 +1,6 @@ +[ + (comment) + (block) + (afx_comment) + (afx_element) +] @fold diff --git a/queries/fusion/highlights.scm b/queries/fusion/highlights.scm new file mode 100644 index 000000000..7108e5705 --- /dev/null +++ b/queries/fusion/highlights.scm @@ -0,0 +1,132 @@ +(comment) @comment @spell + +(afx_comment) @comment @spell + +; 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) @spell + +; identifiers eel +(eel_object_path + (eel_path_identifier) @variable.builtin + (#any-of? @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" @keyword.import + (source_file) @string.special.url) + +(namespace_declaration + "namespace" @keyword.type + (alias_namespace) @module) + +(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) +] @module + +(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 + [ + "?" + ":" + ] @keyword.conditional.ternary) diff --git a/queries/fusion/indents.scm b/queries/fusion/indents.scm new file mode 100644 index 000000000..0ba6cf758 --- /dev/null +++ b/queries/fusion/indents.scm @@ -0,0 +1,24 @@ +[ + (block) + (value_dsl) + (afx_element) + (afx_element_self_closing) + (eel_array) + (eel_object) +] @indent.begin + +(block + end: _ @indent.branch) + +(value_dsl + end: _ @indent.branch) + +(eel_array + end: _ @indent.branch) + +(eel_object + end: _ @indent.branch) + +(afx_closing_element) @indent.branch + +(comment) @indent.ignore diff --git a/runtime/queries/wgsl/injections.scm b/queries/fusion/injections.scm similarity index 64% rename from runtime/queries/wgsl/injections.scm rename to queries/fusion/injections.scm index 3cd6aac8e..085cdb458 100644 --- a/runtime/queries/wgsl/injections.scm +++ b/queries/fusion/injections.scm @@ -1,5 +1,5 @@ ([ - (line_comment) - (block_comment) + (comment) + (afx_comment) ] @injection.content (#set! injection.language "comment")) diff --git a/queries/fusion/locals.scm b/queries/fusion/locals.scm new file mode 100644 index 000000000..d23e0ab46 --- /dev/null +++ b/queries/fusion/locals.scm @@ -0,0 +1,23 @@ +; Fusion base +(block) @local.scope + +(namespace_declaration + (alias_namespace) @local.definition.namespace) + +(property + (path + (path_part) @local.definition.field)) + +(type + namespace: (package_name)? @local.definition.namespace + name: (type_name) @local.definition.type) + +; Eel Expressions +(eel_arrow_function) @local.scope + +(eel_object) @local.scope + +(eel_parameter) @local.definition.parameter + +(eel_object_pair + key: (eel_property_name) @local.definition.field) diff --git a/runtime/queries/gap/folds.scm b/queries/gap/folds.scm similarity index 100% rename from runtime/queries/gap/folds.scm rename to queries/gap/folds.scm diff --git a/runtime/queries/gap/highlights.scm b/queries/gap/highlights.scm similarity index 100% rename from runtime/queries/gap/highlights.scm rename to queries/gap/highlights.scm diff --git a/runtime/queries/fortran/injections.scm b/queries/gap/injections.scm similarity index 100% rename from runtime/queries/fortran/injections.scm rename to queries/gap/injections.scm diff --git a/runtime/queries/gap/locals.scm b/queries/gap/locals.scm similarity index 100% rename from runtime/queries/gap/locals.scm rename to queries/gap/locals.scm diff --git a/runtime/queries/gaptst/folds.scm b/queries/gaptst/folds.scm similarity index 100% rename from runtime/queries/gaptst/folds.scm rename to queries/gaptst/folds.scm diff --git a/runtime/queries/gaptst/highlights.scm b/queries/gaptst/highlights.scm similarity index 100% rename from runtime/queries/gaptst/highlights.scm rename to queries/gaptst/highlights.scm diff --git a/runtime/queries/gaptst/injections.scm b/queries/gaptst/injections.scm similarity index 100% rename from runtime/queries/gaptst/injections.scm rename to queries/gaptst/injections.scm diff --git a/runtime/queries/gdscript/folds.scm b/queries/gdscript/folds.scm similarity index 100% rename from runtime/queries/gdscript/folds.scm rename to queries/gdscript/folds.scm diff --git a/queries/gdscript/highlights.scm b/queries/gdscript/highlights.scm new file mode 100644 index 000000000..bc62bc2f5 --- /dev/null +++ b/queries/gdscript/highlights.scm @@ -0,0 +1,422 @@ +; Basic +(identifier) @variable + +(name) @variable + +(type + (identifier) @type) + +(comment) @comment @spell + +(string_name) @string + +(string) @string + +(float) @number.float + +(integer) @number + +(null) @constant + +(setter) @function + +(getter) @function + +(set_body + "set" @keyword.function) + +(get_body + "get" @keyword.function) + +(static_keyword) @keyword.modifier + +(tool_statement) @keyword + +(breakpoint_statement) @keyword.debug + +(inferred_type) @operator + +[ + (true) + (false) +] @boolean + +[ + (get_node) + (node_path) +] @string.special.url + +(class_name_statement + (name) @type) @keyword + +(const_statement + "const" @keyword.modifier + (name) @constant) + +(expression_statement + (string) @comment @spell) + +; Functions +(constructor_definition + "_init" @constructor) + +(function_definition + (name) @function) + +(parameters + (identifier) @variable.parameter) + +(typed_parameter + (identifier) @variable.parameter) + +(default_parameter + (identifier) @variable.parameter) + +(typed_default_parameter + (identifier) @variable.parameter) + +(call + (identifier) @function.call) + +(call + (identifier) @keyword.import + (#any-of? @keyword.import "preload" "load")) + +; Properties and Methods +; We'll use @property since that's the term Godot uses. +; But, should (source (variable_statement (name))) be @property, too? Since a +; script file is a class in gdscript. +(class_definition + (body + (variable_statement + (name) @property))) + +; Same question but for methods? +(class_definition + (body + (function_definition + (name) @function.method))) + +(attribute_call + (identifier) @function.method.call) + +(attribute_subscript + (identifier) @property) + +(attribute + (_) + (identifier) @property) + +; Identifier naming conventions +; - Make sure the following query is below the attribute queries so that it +; takes precedence on a `(type (attribute (identifier)))` +((identifier) @type + (#lua-match? @type "^[A-Z]")) + +((identifier) @constant + (#lua-match? @constant "^[A-Z][A-Z_0-9]*$")) + +; Enums +(enumerator + left: (identifier) @constant) + +; Special Builtins +((identifier) @variable.builtin + (#any-of? @variable.builtin "self" "super")) + +(attribute_call + (identifier) @keyword.operator + (#eq? @keyword.operator "new")) + +; Match Pattern +[ + (underscore) + (pattern_open_ending) +] @character.special + +; Alternations +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +[ + "," + "." + ":" +] @punctuation.delimiter + +[ + "if" + "elif" + "else" + "match" +] @keyword.conditional + +(pattern_guard + "when" @keyword.conditional) + +[ + "for" + "while" + "break" + "continue" +] @keyword.repeat + +[ + "~" + "-" + "*" + "/" + "%" + "+" + "-" + "<<" + ">>" + "&" + "^" + "|" + "<" + ">" + "==" + "!=" + ">=" + "<=" + "!" + "&&" + "||" + "=" + "+=" + "-=" + "*=" + "/=" + "%=" + "&=" + "|=" + "->" +] @operator + +[ + "and" + "as" + "in" + "is" + "not" + "or" +] @keyword.operator + +[ + "pass" + "class_name" + "extends" + "signal" + "var" + "onready" + "setget" + "remote" + "master" + "puppet" + "remotesync" + "mastersync" + "puppetsync" +] @keyword + +"export" @keyword.import + +[ + "enum" + "class" +] @keyword.type + +"func" @keyword.function + +"return" @keyword.return + +"await" @keyword.coroutine + +(call + (identifier) @keyword.coroutine + (#eq? @keyword.coroutine "yield")) + +; Builtins +; generated from +; - godot commit: fb10e67fef +; - https://github.com/godotengine/godot/blob/fb10e67fef/doc/classes +; - https://github.com/godotengine/godot/blob/fb10e67fef/doc/classes/@GlobalScope.xml +; - https://github.com/godotengine/godot/blob/fb10e67fef/modules/gdscript/doc_classes/@GDScript.xml +; Built-in Annotations +((annotation + "@" @attribute + (identifier) @attribute) + (#any-of? @attribute + ; from modules/gdscript/doc_classes/@GDScript.xml + "export" "export_category" "export_color_no_alpha" "export_dir" "export_enum" + "export_exp_easing" "export_file" "export_flags" "export_flags_2d_navigation" + "export_flags_2d_physics" "export_flags_2d_render" "export_flags_3d_navigation" + "export_flags_3d_physics" "export_flags_3d_render" "export_flags_avoidance" "export_global_dir" + "export_global_file" "export_group" "export_multiline" "export_node_path" "export_placeholder" + "export_range" "export_subgroup" "icon" "onready" "rpc" "static_unload" "tool" "warning_ignore")) + +; Builtin Types +((identifier) @type.builtin + (#any-of? @type.builtin + ; from doc/classes/*.xml + "AABB" "Array" "Basis" "Callable" "Color" "Dictionary" "NodePath" "PackedByteArray" + "PackedColorArray" "PackedFloat32Array" "PackedFloat64Array" "PackedInt32Array" + "PackedInt64Array" "PackedStringArray" "PackedVector2Array" "PackedVector3Array" "Plane" + "Projection" "Quaternion" "RID" "Rect2" "Rect2i" "Signal" "String" "StringName" "Transform2D" + "Transform3D" "Vector2" "Vector2i" "Vector3" "Vector3i" "Vector4" "Vector4i" "bool" "float" + "int" + ; from doc/classes/@GlobalScope.xml + "AudioServer" "CameraServer" "ClassDB" "DisplayServer" "EditorInterface" "Engine" + "EngineDebugger" "GDExtensionManager" "Geometry2D" "Geometry3D" "GodotSharp" "IP" "Input" + "InputMap" "JavaClassWrapper" "JavaScriptBridge" "Marshalls" "NavigationMeshGenerator" + "NavigationServer2D" "NavigationServer3D" "OS" "Performance" "PhysicsServer2D" + "PhysicsServer2DManager" "PhysicsServer3D" "PhysicsServer3DManager" "ProjectSettings" + "RenderingServer" "ResourceLoader" "ResourceSaver" "ResourceUID" "TextServerManager" "ThemeDB" + "Time" "TranslationServer" "WorkerThreadPool" "XRServer")) + +; Builtin Funcs +(call + (identifier) @function.builtin + (#any-of? @function.builtin + ; from doc/classes/@GlobalScope.xml + "abs" "absf" "absi" "acos" "acosh" "angle_difference" "asin" "asinh" "atan" "atan2" "atanh" + "bezier_derivative" "bezier_interpolate" "bytes_to_var" "bytes_to_var_with_objects" "ceil" + "ceilf" "ceili" "clamp" "clampf" "clampi" "cos" "cosh" "cubic_interpolate" + "cubic_interpolate_angle" "cubic_interpolate_angle_in_time" "cubic_interpolate_in_time" + "db_to_linear" "deg_to_rad" "ease" "error_string" "exp" "floor" "floorf" "floori" "fmod" + "fposmod" "hash" "instance_from_id" "inverse_lerp" "is_equal_approx" "is_finite" "is_inf" + "is_instance_id_valid" "is_instance_valid" "is_nan" "is_same" "is_zero_approx" "lerp" + "lerp_angle" "lerpf" "linear_to_db" "log" "max" "maxf" "maxi" "min" "minf" "mini" "move_toward" + "nearest_po2" "pingpong" "posmod" "pow" "print" "print_rich" "print_verbose" "printerr" + "printraw" "prints" "printt" "push_error" "push_warning" "rad_to_deg" "rand_from_seed" "randf" + "randf_range" "randfn" "randi" "randi_range" "randomize" "remap" "rid_allocate_id" + "rid_from_int64" "rotate_toward" "round" "roundf" "roundi" "seed" "sign" "signf" "signi" "sin" + "sinh" "smoothstep" "snapped" "snappedf" "snappedi" "sqrt" "step_decimals" "str" "str_to_var" + "tan" "tanh" "type_convert" "type_string" "typeof" "var_to_bytes" "var_to_bytes_with_objects" + "var_to_str" "weakref" "wrap" "wrapf" "wrapi" + ; from modules/gdscript/doc_classes/@GDScript.xml + "Color8" "assert" "char" "convert" "dict_to_inst" "get_stack" "inst_to_dict" "is_instance_of" + "len" "load" "preload" "print_debug" "print_stack" "range" "type_exists") + ) + +; Builtin Constants +((identifier) @constant.builtin + (#any-of? @constant.builtin + ; from modules/gdscript/doc_classes/@GDScript.xml + "INF" "NAN" "PI" "TAU" + ; from doc/classes/@GlobalScope.xml + "CLOCKWISE" "CORNER_BOTTOM_LEFT" "CORNER_BOTTOM_RIGHT" "CORNER_TOP_LEFT" "CORNER_TOP_RIGHT" + "COUNTERCLOCKWISE" "ERR_ALREADY_EXISTS" "ERR_ALREADY_IN_USE" "ERR_BUG" "ERR_BUSY" + "ERR_CANT_ACQUIRE_RESOURCE" "ERR_CANT_CONNECT" "ERR_CANT_CREATE" "ERR_CANT_FORK" "ERR_CANT_OPEN" + "ERR_CANT_RESOLVE" "ERR_COMPILATION_FAILED" "ERR_CONNECTION_ERROR" "ERR_CYCLIC_LINK" + "ERR_DATABASE_CANT_READ" "ERR_DATABASE_CANT_WRITE" "ERR_DOES_NOT_EXIST" "ERR_DUPLICATE_SYMBOL" + "ERR_FILE_ALREADY_IN_USE" "ERR_FILE_BAD_DRIVE" "ERR_FILE_BAD_PATH" "ERR_FILE_CANT_OPEN" + "ERR_FILE_CANT_READ" "ERR_FILE_CANT_WRITE" "ERR_FILE_CORRUPT" "ERR_FILE_EOF" + "ERR_FILE_MISSING_DEPENDENCIES" "ERR_FILE_NOT_FOUND" "ERR_FILE_NO_PERMISSION" + "ERR_FILE_UNRECOGNIZED" "ERR_HELP" "ERR_INVALID_DATA" "ERR_INVALID_DECLARATION" + "ERR_INVALID_PARAMETER" "ERR_LINK_FAILED" "ERR_LOCKED" "ERR_METHOD_NOT_FOUND" + "ERR_OUT_OF_MEMORY" "ERR_PARAMETER_RANGE_ERROR" "ERR_PARSE_ERROR" "ERR_PRINTER_ON_FIRE" + "ERR_QUERY_FAILED" "ERR_SCRIPT_FAILED" "ERR_SKIP" "ERR_TIMEOUT" "ERR_UNAUTHORIZED" + "ERR_UNAVAILABLE" "ERR_UNCONFIGURED" "EULER_ORDER_XYZ" "EULER_ORDER_XZY" "EULER_ORDER_YXZ" + "EULER_ORDER_YZX" "EULER_ORDER_ZXY" "EULER_ORDER_ZYX" "FAILED" "HORIZONTAL" + "HORIZONTAL_ALIGNMENT_CENTER" "HORIZONTAL_ALIGNMENT_FILL" "HORIZONTAL_ALIGNMENT_LEFT" + "HORIZONTAL_ALIGNMENT_RIGHT" "INLINE_ALIGNMENT_BASELINE_TO" "INLINE_ALIGNMENT_BOTTOM" + "INLINE_ALIGNMENT_BOTTOM_TO" "INLINE_ALIGNMENT_CENTER" "INLINE_ALIGNMENT_CENTER_TO" + "INLINE_ALIGNMENT_IMAGE_MASK" "INLINE_ALIGNMENT_TEXT_MASK" "INLINE_ALIGNMENT_TOP" + "INLINE_ALIGNMENT_TOP_TO" "INLINE_ALIGNMENT_TO_BASELINE" "INLINE_ALIGNMENT_TO_BOTTOM" + "INLINE_ALIGNMENT_TO_CENTER" "INLINE_ALIGNMENT_TO_TOP" "JOY_AXIS_INVALID" "JOY_AXIS_LEFT_X" + "JOY_AXIS_LEFT_Y" "JOY_AXIS_MAX" "JOY_AXIS_RIGHT_X" "JOY_AXIS_RIGHT_Y" "JOY_AXIS_SDL_MAX" + "JOY_AXIS_TRIGGER_LEFT" "JOY_AXIS_TRIGGER_RIGHT" "JOY_BUTTON_A" "JOY_BUTTON_B" "JOY_BUTTON_BACK" + "JOY_BUTTON_DPAD_DOWN" "JOY_BUTTON_DPAD_LEFT" "JOY_BUTTON_DPAD_RIGHT" "JOY_BUTTON_DPAD_UP" + "JOY_BUTTON_GUIDE" "JOY_BUTTON_INVALID" "JOY_BUTTON_LEFT_SHOULDER" "JOY_BUTTON_LEFT_STICK" + "JOY_BUTTON_MAX" "JOY_BUTTON_MISC1" "JOY_BUTTON_PADDLE1" "JOY_BUTTON_PADDLE2" + "JOY_BUTTON_PADDLE3" "JOY_BUTTON_PADDLE4" "JOY_BUTTON_RIGHT_SHOULDER" "JOY_BUTTON_RIGHT_STICK" + "JOY_BUTTON_SDL_MAX" "JOY_BUTTON_START" "JOY_BUTTON_TOUCHPAD" "JOY_BUTTON_X" "JOY_BUTTON_Y" + "KEY_0" "KEY_1" "KEY_2" "KEY_3" "KEY_4" "KEY_5" "KEY_6" "KEY_7" "KEY_8" "KEY_9" "KEY_A" + "KEY_ALT" "KEY_AMPERSAND" "KEY_APOSTROPHE" "KEY_ASCIICIRCUM" "KEY_ASCIITILDE" "KEY_ASTERISK" + "KEY_AT" "KEY_B" "KEY_BACK" "KEY_BACKSLASH" "KEY_BACKSPACE" "KEY_BACKTAB" "KEY_BAR" + "KEY_BRACELEFT" "KEY_BRACERIGHT" "KEY_BRACKETLEFT" "KEY_BRACKETRIGHT" "KEY_C" "KEY_CAPSLOCK" + "KEY_CLEAR" "KEY_CODE_MASK" "KEY_COLON" "KEY_COMMA" "KEY_CTRL" "KEY_D" "KEY_DELETE" "KEY_DOLLAR" + "KEY_DOWN" "KEY_E" "KEY_END" "KEY_ENTER" "KEY_EQUAL" "KEY_ESCAPE" "KEY_EXCLAM" "KEY_F" "KEY_F1" + "KEY_F10" "KEY_F11" "KEY_F12" "KEY_F13" "KEY_F14" "KEY_F15" "KEY_F16" "KEY_F17" "KEY_F18" + "KEY_F19" "KEY_F2" "KEY_F20" "KEY_F21" "KEY_F22" "KEY_F23" "KEY_F24" "KEY_F25" "KEY_F26" + "KEY_F27" "KEY_F28" "KEY_F29" "KEY_F3" "KEY_F30" "KEY_F31" "KEY_F32" "KEY_F33" "KEY_F34" + "KEY_F35" "KEY_F4" "KEY_F5" "KEY_F6" "KEY_F7" "KEY_F8" "KEY_F9" "KEY_FAVORITES" "KEY_FORWARD" + "KEY_G" "KEY_GLOBE" "KEY_GREATER" "KEY_H" "KEY_HELP" "KEY_HOME" "KEY_HOMEPAGE" "KEY_HYPER" + "KEY_I" "KEY_INSERT" "KEY_J" "KEY_JIS_EISU" "KEY_JIS_KANA" "KEY_K" "KEY_KEYBOARD" "KEY_KP_0" + "KEY_KP_1" "KEY_KP_2" "KEY_KP_3" "KEY_KP_4" "KEY_KP_5" "KEY_KP_6" "KEY_KP_7" "KEY_KP_8" + "KEY_KP_9" "KEY_KP_ADD" "KEY_KP_DIVIDE" "KEY_KP_ENTER" "KEY_KP_MULTIPLY" "KEY_KP_PERIOD" + "KEY_KP_SUBTRACT" "KEY_L" "KEY_LAUNCH0" "KEY_LAUNCH1" "KEY_LAUNCH2" "KEY_LAUNCH3" "KEY_LAUNCH4" + "KEY_LAUNCH5" "KEY_LAUNCH6" "KEY_LAUNCH7" "KEY_LAUNCH8" "KEY_LAUNCH9" "KEY_LAUNCHA" + "KEY_LAUNCHB" "KEY_LAUNCHC" "KEY_LAUNCHD" "KEY_LAUNCHE" "KEY_LAUNCHF" "KEY_LAUNCHMAIL" + "KEY_LAUNCHMEDIA" "KEY_LEFT" "KEY_LESS" "KEY_LOCATION_LEFT" "KEY_LOCATION_RIGHT" + "KEY_LOCATION_UNSPECIFIED" "KEY_M" "KEY_MASK_ALT" "KEY_MASK_CMD_OR_CTRL" "KEY_MASK_CTRL" + "KEY_MASK_GROUP_SWITCH" "KEY_MASK_KPAD" "KEY_MASK_META" "KEY_MASK_SHIFT" "KEY_MEDIANEXT" + "KEY_MEDIAPLAY" "KEY_MEDIAPREVIOUS" "KEY_MEDIARECORD" "KEY_MEDIASTOP" "KEY_MENU" "KEY_META" + "KEY_MINUS" "KEY_MODIFIER_MASK" "KEY_N" "KEY_NONE" "KEY_NUMBERSIGN" "KEY_NUMLOCK" "KEY_O" + "KEY_OPENURL" "KEY_P" "KEY_PAGEDOWN" "KEY_PAGEUP" "KEY_PARENLEFT" "KEY_PARENRIGHT" "KEY_PAUSE" + "KEY_PERCENT" "KEY_PERIOD" "KEY_PLUS" "KEY_PRINT" "KEY_Q" "KEY_QUESTION" "KEY_QUOTEDBL" + "KEY_QUOTELEFT" "KEY_R" "KEY_REFRESH" "KEY_RIGHT" "KEY_S" "KEY_SCROLLLOCK" "KEY_SEARCH" + "KEY_SECTION" "KEY_SEMICOLON" "KEY_SHIFT" "KEY_SLASH" "KEY_SPACE" "KEY_SPECIAL" "KEY_STANDBY" + "KEY_STOP" "KEY_SYSREQ" "KEY_T" "KEY_TAB" "KEY_U" "KEY_UNDERSCORE" "KEY_UNKNOWN" "KEY_UP" + "KEY_V" "KEY_VOLUMEDOWN" "KEY_VOLUMEMUTE" "KEY_VOLUMEUP" "KEY_W" "KEY_X" "KEY_Y" "KEY_YEN" + "KEY_Z" "METHOD_FLAGS_DEFAULT" "METHOD_FLAG_CONST" "METHOD_FLAG_EDITOR" "METHOD_FLAG_NORMAL" + "METHOD_FLAG_OBJECT_CORE" "METHOD_FLAG_STATIC" "METHOD_FLAG_VARARG" "METHOD_FLAG_VIRTUAL" + "MIDI_MESSAGE_ACTIVE_SENSING" "MIDI_MESSAGE_AFTERTOUCH" "MIDI_MESSAGE_CHANNEL_PRESSURE" + "MIDI_MESSAGE_CONTINUE" "MIDI_MESSAGE_CONTROL_CHANGE" "MIDI_MESSAGE_NONE" + "MIDI_MESSAGE_NOTE_OFF" "MIDI_MESSAGE_NOTE_ON" "MIDI_MESSAGE_PITCH_BEND" + "MIDI_MESSAGE_PROGRAM_CHANGE" "MIDI_MESSAGE_QUARTER_FRAME" "MIDI_MESSAGE_SONG_POSITION_POINTER" + "MIDI_MESSAGE_SONG_SELECT" "MIDI_MESSAGE_START" "MIDI_MESSAGE_STOP" + "MIDI_MESSAGE_SYSTEM_EXCLUSIVE" "MIDI_MESSAGE_SYSTEM_RESET" "MIDI_MESSAGE_TIMING_CLOCK" + "MIDI_MESSAGE_TUNE_REQUEST" "MOUSE_BUTTON_LEFT" "MOUSE_BUTTON_MASK_LEFT" + "MOUSE_BUTTON_MASK_MB_XBUTTON1" "MOUSE_BUTTON_MASK_MB_XBUTTON2" "MOUSE_BUTTON_MASK_MIDDLE" + "MOUSE_BUTTON_MASK_RIGHT" "MOUSE_BUTTON_MIDDLE" "MOUSE_BUTTON_NONE" "MOUSE_BUTTON_RIGHT" + "MOUSE_BUTTON_WHEEL_DOWN" "MOUSE_BUTTON_WHEEL_LEFT" "MOUSE_BUTTON_WHEEL_RIGHT" + "MOUSE_BUTTON_WHEEL_UP" "MOUSE_BUTTON_XBUTTON1" "MOUSE_BUTTON_XBUTTON2" "OK" "OP_ADD" "OP_AND" + "OP_BIT_AND" "OP_BIT_NEGATE" "OP_BIT_OR" "OP_BIT_XOR" "OP_DIVIDE" "OP_EQUAL" "OP_GREATER" + "OP_GREATER_EQUAL" "OP_IN" "OP_LESS" "OP_LESS_EQUAL" "OP_MAX" "OP_MODULE" "OP_MULTIPLY" + "OP_NEGATE" "OP_NOT" "OP_NOT_EQUAL" "OP_OR" "OP_POSITIVE" "OP_POWER" "OP_SHIFT_LEFT" + "OP_SHIFT_RIGHT" "OP_SUBTRACT" "OP_XOR" "PROPERTY_HINT_ARRAY_TYPE" + "PROPERTY_HINT_COLOR_NO_ALPHA" "PROPERTY_HINT_DIR" "PROPERTY_HINT_ENUM" + "PROPERTY_HINT_ENUM_SUGGESTION" "PROPERTY_HINT_EXPRESSION" "PROPERTY_HINT_EXP_EASING" + "PROPERTY_HINT_FILE" "PROPERTY_HINT_FLAGS" "PROPERTY_HINT_GLOBAL_DIR" + "PROPERTY_HINT_GLOBAL_FILE" "PROPERTY_HINT_GLOBAL_SAVE_FILE" + "PROPERTY_HINT_HIDE_QUATERNION_EDIT" "PROPERTY_HINT_INT_IS_OBJECTID" + "PROPERTY_HINT_INT_IS_POINTER" "PROPERTY_HINT_LAYERS_2D_NAVIGATION" + "PROPERTY_HINT_LAYERS_2D_PHYSICS" "PROPERTY_HINT_LAYERS_2D_RENDER" + "PROPERTY_HINT_LAYERS_3D_NAVIGATION" "PROPERTY_HINT_LAYERS_3D_PHYSICS" + "PROPERTY_HINT_LAYERS_3D_RENDER" "PROPERTY_HINT_LAYERS_AVOIDANCE" "PROPERTY_HINT_LINK" + "PROPERTY_HINT_LOCALE_ID" "PROPERTY_HINT_LOCALIZABLE_STRING" "PROPERTY_HINT_MAX" + "PROPERTY_HINT_MULTILINE_TEXT" "PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE" + "PROPERTY_HINT_NODE_PATH_VALID_TYPES" "PROPERTY_HINT_NODE_TYPE" "PROPERTY_HINT_NONE" + "PROPERTY_HINT_OBJECT_ID" "PROPERTY_HINT_OBJECT_TOO_BIG" "PROPERTY_HINT_PASSWORD" + "PROPERTY_HINT_PLACEHOLDER_TEXT" "PROPERTY_HINT_RANGE" "PROPERTY_HINT_RESOURCE_TYPE" + "PROPERTY_HINT_SAVE_FILE" "PROPERTY_HINT_TYPE_STRING" "PROPERTY_USAGE_ALWAYS_DUPLICATE" + "PROPERTY_USAGE_ARRAY" "PROPERTY_USAGE_CATEGORY" "PROPERTY_USAGE_CHECKABLE" + "PROPERTY_USAGE_CHECKED" "PROPERTY_USAGE_CLASS_IS_BITFIELD" "PROPERTY_USAGE_CLASS_IS_ENUM" + "PROPERTY_USAGE_DEFAULT" "PROPERTY_USAGE_DEFERRED_SET_RESOURCE" "PROPERTY_USAGE_EDITOR" + "PROPERTY_USAGE_EDITOR_BASIC_SETTING" "PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT" + "PROPERTY_USAGE_GROUP" "PROPERTY_USAGE_HIGH_END_GFX" "PROPERTY_USAGE_INTERNAL" + "PROPERTY_USAGE_KEYING_INCREMENTS" "PROPERTY_USAGE_NEVER_DUPLICATE" + "PROPERTY_USAGE_NIL_IS_VARIANT" "PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT" "PROPERTY_USAGE_NONE" + "PROPERTY_USAGE_NO_EDITOR" "PROPERTY_USAGE_NO_INSTANCE_STATE" "PROPERTY_USAGE_READ_ONLY" + "PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT" "PROPERTY_USAGE_RESTART_IF_CHANGED" + "PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE" "PROPERTY_USAGE_SCRIPT_VARIABLE" "PROPERTY_USAGE_SECRET" + "PROPERTY_USAGE_STORAGE" "PROPERTY_USAGE_STORE_IF_NULL" "PROPERTY_USAGE_SUBGROUP" + "PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED" "SIDE_BOTTOM" "SIDE_LEFT" "SIDE_RIGHT" "SIDE_TOP" + "TYPE_AABB" "TYPE_ARRAY" "TYPE_BASIS" "TYPE_BOOL" "TYPE_CALLABLE" "TYPE_COLOR" "TYPE_DICTIONARY" + "TYPE_FLOAT" "TYPE_INT" "TYPE_MAX" "TYPE_NIL" "TYPE_NODE_PATH" "TYPE_OBJECT" + "TYPE_PACKED_BYTE_ARRAY" "TYPE_PACKED_COLOR_ARRAY" "TYPE_PACKED_FLOAT32_ARRAY" + "TYPE_PACKED_FLOAT64_ARRAY" "TYPE_PACKED_INT32_ARRAY" "TYPE_PACKED_INT64_ARRAY" + "TYPE_PACKED_STRING_ARRAY" "TYPE_PACKED_VECTOR2_ARRAY" "TYPE_PACKED_VECTOR3_ARRAY" "TYPE_PLANE" + "TYPE_PROJECTION" "TYPE_QUATERNION" "TYPE_RECT2" "TYPE_RECT2I" "TYPE_RID" "TYPE_SIGNAL" + "TYPE_STRING" "TYPE_STRING_NAME" "TYPE_TRANSFORM2D" "TYPE_TRANSFORM3D" "TYPE_VECTOR2" + "TYPE_VECTOR2I" "TYPE_VECTOR3" "TYPE_VECTOR3I" "TYPE_VECTOR4" "TYPE_VECTOR4I" "VERTICAL" + "VERTICAL_ALIGNMENT_BOTTOM" "VERTICAL_ALIGNMENT_CENTER" "VERTICAL_ALIGNMENT_FILL" + "VERTICAL_ALIGNMENT_TOP")) diff --git a/runtime/queries/gdscript/indents.scm b/queries/gdscript/indents.scm similarity index 100% rename from runtime/queries/gdscript/indents.scm rename to queries/gdscript/indents.scm diff --git a/runtime/queries/func/injections.scm b/queries/gdscript/injections.scm similarity index 100% rename from runtime/queries/func/injections.scm rename to queries/gdscript/injections.scm diff --git a/runtime/queries/gdscript/locals.scm b/queries/gdscript/locals.scm similarity index 100% rename from runtime/queries/gdscript/locals.scm rename to queries/gdscript/locals.scm diff --git a/queries/gdshader/highlights.scm b/queries/gdshader/highlights.scm new file mode 100644 index 000000000..c93fd4721 --- /dev/null +++ b/queries/gdshader/highlights.scm @@ -0,0 +1,142 @@ +[ + "render_mode" + "shader_type" + "group_uniforms" + "global" + "instance" + "const" + "varying" + "uniform" +] @keyword + +"struct" @keyword.type + +[ + (precision_qualifier) + (interpolation_qualifier) +] @keyword.modifier + +[ + "in" + "out" + "inout" +] @keyword.modifier + +[ + "while" + "for" +] @keyword.repeat + +[ + "continue" + "break" + "return" +] @keyword.return + +[ + "if" + "else" + "switch" + "case" + "default" +] @keyword.conditional + +[ + "#" + "include" +] @keyword.directive + +(string) @string + +[ + "=" + "+=" + "-=" + "!" + "~" + "+" + "-" + "*" + "/" + "%" + "||" + "&&" + "|" + "^" + "&" + "==" + "!=" + ">" + ">=" + "<=" + "<" + "<<" + ">>" + "++" + "--" +] @operator + +(boolean) @boolean + +(integer) @number + +(float) @number.float + +[ + "." + "," + ";" +] @punctuation.delimiter + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +(builtin_type) @type.builtin + +(ident_type) @type.definition + +[ + (shader_type) + (render_mode) + (hint_name) +] @attribute + +(builtin_variable) @constant.builtin + +(builtin_function) @function.builtin + +(group_uniforms_declaration + group_name: (ident) @property + subgroup_name: (ident) @property) + +(struct_declaration + name: (ident) @type) + +(struct_member + name: (ident) @property) + +(function_declaration + name: (ident) @function) + +(parameter + name: (ident) @variable.parameter) + +(member_expr + member: (ident) @property) + +(call_expr + function: [ + (ident) + (builtin_type) + ] @function) + +(call_expr + function: (builtin_type) @function.call) + +(comment) @comment @spell diff --git a/runtime/queries/gap/injections.scm b/queries/gdshader/injections.scm similarity index 100% rename from runtime/queries/gap/injections.scm rename to queries/gdshader/injections.scm diff --git a/runtime/queries/git_config/folds.scm b/queries/git_config/folds.scm similarity index 100% rename from runtime/queries/git_config/folds.scm rename to queries/git_config/folds.scm diff --git a/runtime/queries/git_config/highlights.scm b/queries/git_config/highlights.scm similarity index 89% rename from runtime/queries/git_config/highlights.scm rename to queries/git_config/highlights.scm index 557ac60ec..6b37e9090 100644 --- a/runtime/queries/git_config/highlights.scm +++ b/queries/git_config/highlights.scm @@ -7,7 +7,7 @@ ((section_header (section_name) @keyword.import (subsection_name)) - (#any-of? @keyword.import "includeIf" "includeif")) + (#eq? @keyword.import "includeIf")) (variable (name) @property) @@ -47,7 +47,7 @@ ((variable (name) @_name value: (string) @string.special.url) - (#any-of? @_name "insteadOf" "insteadof")) + (#eq? @_name "insteadOf")) ; Punctuation [ diff --git a/runtime/queries/git_config/injections.scm b/queries/git_config/injections.scm similarity index 92% rename from runtime/queries/git_config/injections.scm rename to queries/git_config/injections.scm index 8b4d69282..7bda6979c 100644 --- a/runtime/queries/git_config/injections.scm +++ b/queries/git_config/injections.scm @@ -4,7 +4,7 @@ ((variable (name) @_name value: (string) @injection.content) - (#any-of? @_name "cmd" "command" "textconv" "sendmailCmd" "sendmailcmd") + (#any-of? @_name "cmd" "command" "textconv" "sendmailCmd") (#set! injection.language "bash")) (section @@ -29,7 +29,7 @@ (name) @_name value: (string) @injection.content) (#eq? @_interactive "interactive") - (#any-of? @_name "diffFilter" "difffilter") + (#eq? @_name "diffFilter") (#set! injection.language "bash")) ; https://github.com/git-lfs/git-lfs diff --git a/runtime/queries/git_rebase/highlights.scm b/queries/git_rebase/highlights.scm similarity index 100% rename from runtime/queries/git_rebase/highlights.scm rename to queries/git_rebase/highlights.scm diff --git a/runtime/queries/git_rebase/injections.scm b/queries/git_rebase/injections.scm similarity index 100% rename from runtime/queries/git_rebase/injections.scm rename to queries/git_rebase/injections.scm diff --git a/runtime/queries/gitattributes/highlights.scm b/queries/gitattributes/highlights.scm similarity index 100% rename from runtime/queries/gitattributes/highlights.scm rename to queries/gitattributes/highlights.scm diff --git a/runtime/queries/gdscript/injections.scm b/queries/gitattributes/injections.scm similarity index 100% rename from runtime/queries/gdscript/injections.scm rename to queries/gitattributes/injections.scm diff --git a/runtime/queries/gitattributes/locals.scm b/queries/gitattributes/locals.scm similarity index 100% rename from runtime/queries/gitattributes/locals.scm rename to queries/gitattributes/locals.scm diff --git a/runtime/queries/gitcommit/highlights.scm b/queries/gitcommit/highlights.scm similarity index 100% rename from runtime/queries/gitcommit/highlights.scm rename to queries/gitcommit/highlights.scm diff --git a/runtime/queries/gitcommit/injections.scm b/queries/gitcommit/injections.scm similarity index 100% rename from runtime/queries/gitcommit/injections.scm rename to queries/gitcommit/injections.scm diff --git a/runtime/queries/gitignore/highlights.scm b/queries/gitignore/highlights.scm similarity index 100% rename from runtime/queries/gitignore/highlights.scm rename to queries/gitignore/highlights.scm diff --git a/runtime/queries/gdshader/injections.scm b/queries/gitignore/injections.scm similarity index 100% rename from runtime/queries/gdshader/injections.scm rename to queries/gitignore/injections.scm diff --git a/runtime/queries/gleam/folds.scm b/queries/gleam/folds.scm similarity index 100% rename from runtime/queries/gleam/folds.scm rename to queries/gleam/folds.scm diff --git a/runtime/queries/gleam/highlights.scm b/queries/gleam/highlights.scm similarity index 98% rename from runtime/queries/gleam/highlights.scm rename to queries/gleam/highlights.scm index f25926f92..5238c601b 100644 --- a/runtime/queries/gleam/highlights.scm +++ b/queries/gleam/highlights.scm @@ -5,7 +5,6 @@ "panic" "todo" "use" - "echo" ] @keyword "type" @keyword.type @@ -106,7 +105,7 @@ (string) @string ; Bit Strings -(bit_array_segment) @string.special +(bit_string_segment) @string.special ; Numbers (integer) @number diff --git a/runtime/queries/gleam/indents.scm b/queries/gleam/indents.scm similarity index 92% rename from runtime/queries/gleam/indents.scm rename to queries/gleam/indents.scm index a8fa961d5..c79854508 100644 --- a/runtime/queries/gleam/indents.scm +++ b/queries/gleam/indents.scm @@ -7,13 +7,15 @@ (constant) (external_function) (function) + (import) (let) (list) + (constant) + (function) (type_definition) (type_alias) (todo) (tuple) - (unqualified_imports) ] @indent.begin [ diff --git a/runtime/queries/gleam/injections.scm b/queries/gleam/injections.scm similarity index 100% rename from runtime/queries/gleam/injections.scm rename to queries/gleam/injections.scm diff --git a/runtime/queries/gleam/locals.scm b/queries/gleam/locals.scm similarity index 91% rename from runtime/queries/gleam/locals.scm rename to queries/gleam/locals.scm index 0058b660e..39909a4aa 100644 --- a/runtime/queries/gleam/locals.scm +++ b/queries/gleam/locals.scm @@ -27,5 +27,8 @@ ; Block Scope (block) @local.scope +; Function Body Scope +(function_body) @local.scope + ; Case Scope (case_clause) @local.scope diff --git a/runtime/queries/glimmer/folds.scm b/queries/glimmer/folds.scm similarity index 100% rename from runtime/queries/glimmer/folds.scm rename to queries/glimmer/folds.scm diff --git a/runtime/queries/glimmer/highlights.scm b/queries/glimmer/highlights.scm similarity index 100% rename from runtime/queries/glimmer/highlights.scm rename to queries/glimmer/highlights.scm diff --git a/runtime/queries/glimmer/indents.scm b/queries/glimmer/indents.scm similarity index 100% rename from runtime/queries/glimmer/indents.scm rename to queries/glimmer/indents.scm diff --git a/queries/glimmer/injections.scm b/queries/glimmer/injections.scm new file mode 100644 index 000000000..30b438682 --- /dev/null +++ b/queries/glimmer/injections.scm @@ -0,0 +1,21 @@ +; comments +((comment_statement) @injection.content + (#set! injection.language "comment")) + +;