diff --git a/.github/workflows/check_query_files.yml b/.github/workflows/check_query_files.yml deleted file mode 100644 index 053bb0db..00000000 --- a/.github/workflows/check_query_files.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Check loading of syntax files - -on: - push: - pull_request: - schedule: - - cron: '0 0 * * *' # every day at midnight - -jobs: - luacheck: - name: Check Query Files - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - - - name: Install tree-sitter CLI - run: npm i -g tree-sitter-cli - - - name: Prepare - env: - NVIM_TAG: stable - run: | - sudo apt-get update && sudo apt-get install libfuse2 - sudo add-apt-repository universe - wget https://github.com/neovim/neovim/releases/download/${NVIM_TAG}/nvim.appimage - chmod u+x nvim.appimage - mkdir -p ~/.local/share/nvim/site/pack/nvim-treesitter-textobject/start - ln -s $(pwd) ~/.local/share/nvim/site/pack/nvim-treesitter-textobject/start - mkdir -p ~/.local/share/nvim/site/pack/nvim-treesitter/start - cd ~/.local/share/nvim/site/pack/nvim-treesitter/start - git clone https://github.com/nvim-treesitter/nvim-treesitter.git - - - name: Compile parsers - run: ./nvim.appimage --headless -c "TSInstallSync all" -c "q" - - - name: Check query files - run: ./nvim.appimage --headless -c "luafile ./scripts/check-queries.lua" -c "q" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4edfe3cf..686eb274 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,53 +1,40 @@ -name: Linting and style checking +name: Lint -on: [push, pull_request] +on: + push: + branches: + - "main" + pull_request: + branches: + - "main" + workflow_dispatch: jobs: - luacheck: - name: Luacheck + lua: + name: Lint Lua files runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - name: Prepare + - name: Format run: | - sudo apt-get update - sudo add-apt-repository universe - sudo apt install luarocks -y - sudo luarocks install luacheck + make formatlua + git diff --exit-code - - name: Run Luacheck - run: sudo ./scripts/style-check.sh + - name: Lint + run: make checklua - stylua: - name: StyLua - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Lint with stylua - uses: JohnnyMorganz/stylua-action@v2 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: latest - args: --check . - - format-queries: - name: Lint queries + queries: + name: Lint query files runs-on: ubuntu-latest - env: - NVIM_TAG: stable steps: - uses: actions/checkout@v4 - - name: Prepare - run: | - bash ./scripts/ci-install-ubuntu-latest.sh - wget -P scripts/ https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/main/scripts/format-queries.lua - mkdir -p ~/.local/share/nvim/site/pack/nvim-treesitter/start - cd ~/.local/share/nvim/site/pack/nvim-treesitter/start - git clone https://github.com/nvim-treesitter/nvim-treesitter.git - - name: Lint + - name: Format run: | - nvim --headless -c "TSInstallSync query" -c "q" - nvim -l scripts/format-queries.lua queries + make formatquery git diff --exit-code + + - name: Lint + run: make lintquery + diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..5d89771c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,71 @@ +name: Tests + +on: + push: + branches: + - "main" + pull_request: + branches: + - "main" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-build-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +defaults: + run: + shell: bash + +jobs: + check_compilation: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + nvim_tag: [nightly] + name: ${{ matrix.os }} + runs-on: ${{ matrix.os }} + env: + NVIM_TS_DIR: .test-deps/nvim-treesitter + + 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: Install nvim-treesitter + uses: actions/checkout@v4 + with: + repository: nvim-treesitter/nvim-treesitter + ref: main + path: ${{ env.NVIM_TS_DIR }} + + - name: Setup Parsers Cache + id: parsers-cache + uses: actions/cache@v4 + with: + path: ~/.local/share/nvim/site/parser/ + key: parsers-${{ hashFiles('parsers.lua') }} + + - name: Compile parsers + if: steps.parsers-cache.outputs.cache-hit != 'true' + working-directory: ${{ env.NVIM_TS_DIR }} + run: nvim -l ./scripts/install-parsers.lua --max-jobs=10 + + - name: Lint docs + run: | + make docs + git diff --exit-code + + - name: Check queries + run: make checkquery + + - name: Run tests + run: make tests diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index cf0d912b..00000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Tests - -on: - push: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - branches: - - 'master' - -# Cancel any in-progress CI runs for a PR if it is updated -concurrency: - group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} - cancel-in-progress: true - -jobs: - check_compilation: - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - cc: [gcc] - nvim_tag: [stable, nightly] - - name: Run tests - runs-on: ${{ matrix.os }} - env: - CC: ${{ matrix.cc }} - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - - - name: Install tree-sitter CLI - run: npm i -g tree-sitter-cli - - - name: Test Dependencies - run: | - mkdir -p ~/.local/share/nvim/site/pack/ci/opt - cd ~/.local/share/nvim/site/pack/ci/opt - git clone https://github.com/nvim-lua/plenary.nvim - git clone https://github.com/nvim-treesitter/nvim-treesitter - - name: Install and prepare Neovim - env: - NVIM_TAG: ${{ matrix.nvim_tag }} - run: | - bash ./scripts/ci-install-${{ matrix.os }}.sh - - name: Setup Parsers Cache - id: parsers-cache - uses: actions/cache@v3 - with: - path: | - ./parser/ - ~/AppData/Local/nvim/pack/nvim-treesitter/start/nvim-treesitter/parser/ - key: ${{ matrix.os }}-${{ matrix.cc }}-parsers-v1-${{ hashFiles('./lockfile.json', './lua/nvim-treesitter/parsers.lua', './lua/nvim-treesitter/install.lua', './lua/nvim-treesitter/shell_selectors.lua') }} - - - name: Compile parsers Unix like - if: ${{ matrix.os != 'windows-latest' && steps.parsers-cache.outputs.cache-hit != 'true' }} - run: | - nvim --headless -c "TSInstallSync all" -c "q" - - name: Tests - run: PATH=/usr/local/bin:$PATH ./scripts/run_tests.sh diff --git a/.github/workflows/update-readme.yml b/.github/workflows/update-readme.yml deleted file mode 100644 index ede52333..00000000 --- a/.github/workflows/update-readme.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Check README parser info - -on: - push: - branches: - - master - -jobs: - update-readme: - name: Update README.md - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - - - name: Install tree-sitter CLI - run: npm i -g tree-sitter-cli - - - name: Prepare - run: | - sudo apt-get update && sudo apt-get install libfuse2 - sudo add-apt-repository universe - wget https://github.com/neovim/neovim/releases/download/nightly/nvim.appimage - chmod u+x nvim.appimage - mkdir -p ~/.local/share/nvim/site/pack/nvim-treesitter-textobject/start - ln -s $(pwd) ~/.local/share/nvim/site/pack/nvim-treesitter-textobject/start - mkdir -p ~/.local/share/nvim/site/pack/nvim-treesitter/start - cd ~/.local/share/nvim/site/pack/nvim-treesitter/start - git clone https://github.com/nvim-treesitter/nvim-treesitter.git - - - name: Compile parsers - run: ./nvim.appimage --headless -c "TSInstallSync all" -c "q" - - # inspired by nvim-lspconfigs - - name: Check README - run: | - git config user.email "actions@github" - git config user.name "Github Actions" - ./nvim.appimage --headless -c "luafile ./scripts/update-readme.lua" -c "q" || echo "Needs update" - git add README.md - git commit -m "docs: update queries in README" || echo 'No commit necessary!' - git clean -xf - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 - with: - commit-message: "docs: update queries in README" - title: "docs: update queries in README" - branch: update-readme - base: ${{ github.head_ref }} diff --git a/.gitignore b/.gitignore index 9713deeb..ca538329 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +.test-deps doc/tags .luacheckcache /tags +nvim.appimage +nvim-linux-x86_64* +nvim-macos* +nvim-win64* diff --git a/.luacheckrc b/.luacheckrc deleted file mode 100644 index f3a360ec..00000000 --- a/.luacheckrc +++ /dev/null @@ -1,17 +0,0 @@ --- Rerun tests only if their modification time changed. -cache = true - --- 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 - "431", -- Shadowing a variable - "122" -- Indirectly setting a readonly global -} - --- Global objects defined by the C code -read_globals = { - "vim", -} diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 00000000..e4186720 --- /dev/null +++ b/.luarc.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json", + "runtime": { + "version": "LuaJIT" + }, + "workspace": { + "library": [ + "$VIMRUNTIME", + "${3rd}/busted/library" + ], + "ignoreDir": [ + ".test-deps", + "scripts", + "tests" + ], + "checkThirdParty": "Disable" + }, + "diagnostics": { + "groupFileStatus": { + "strict": "Opened", + "strong": "Opened" + }, + "groupSeverity": { + "strong": "Warning", + "strict": "Warning" + }, + "unusedLocalExclude": [ "_*" ] + } +} diff --git a/.stylua.toml b/.stylua.toml index 364ef9c9..a2b34475 100644 --- a/.stylua.toml +++ b/.stylua.toml @@ -1,3 +1,6 @@ +column_width = 100 +line_endings = "Unix" indent_type = "Spaces" indent_width = 2 -no_call_parentheses = true +quote_style = "AutoPreferSingle" +call_parentheses = "Always" diff --git a/.tsqueryrc.json b/.tsqueryrc.json new file mode 100644 index 00000000..3ac64072 --- /dev/null +++ b/.tsqueryrc.json @@ -0,0 +1,245 @@ +{ + "$schema": "https://raw.githubusercontent.com/ribru17/ts_query_ls/refs/heads/master/schemas/config.json", + "parser_install_directories": ["${HOME}/.local/share/nvim/site/parser"], + "parser_aliases": { + "ecma": "javascript", + "jsx": "javascript" + }, + "valid_captures": { + "textobjects": { + "attribute.inner": "", + "attribute.outer": "", + "function.inner": "", + "function.outer": "", + "class.inner": "", + "class.outer": "", + "conditional.inner": "", + "conditional.outer": "", + "loop.inner": "", + "loop.outer": "", + "call.inner": "", + "call.outer": "", + "block.inner": "", + "block.outer": "", + "parameter.inner": "", + "parameter.outer": "", + "regex.inner": "", + "regex.outer": "", + "comment.inner": "", + "comment.outer": "", + "assignment.inner": "", + "assignment.outer": "", + "return.inner": "", + "return.outer": "", + + "frame.inner": "", + "frame.outer": "", + + "statement.outer": "", + "scopename.inner": "", + "number.inner": "", + + "assignment.lhs": "", + "assignment.rhs": "" + } + }, + "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": "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" + }, + { + "type": "string", + "arity": "variadic" + } + ], + "description": "match any of the given node types against all ancestors of a node" + }, + "has-parent": { + "parameters": [ + { + "type": "capture", + "arity": "required" + }, + { + "type": "any", + "arity": "required" + }, + { + "type": "any", + "arity": "variadic" + } + ], + "description": "match any of the given node types against the direct ancestor of a node" + } + }, + "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" + }, + { + "type": "string", + "arity": "required" + }, + { + "type": "string", + "arity": "required" + }, + { + "type": "string", + "arity": "required" + } + ], + "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" + }, + { + "type": "string", + "arity": "optional" + }, + { + "type": "string", + "arity": "optional" + }, + { + "type": "string", + "arity": "optional" + } + ], + "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 64685cbe..96f8c139 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,14 +51,8 @@ Some nodes have more captures available: ### Automatic README Generation -You don't have to update the support matrix in the README manually. It's -generated by a CI job that runs on pushes to master. +To update the README after adding new textobjects, run `make docs`. ### Query file format -Please use the query file formatter found -[here](https://github.com/nvim-treesitter/nvim-treesitter/blob/main/scripts/format-queries.lua). -There is a CI check that ensures all `.scm` files follow this format. Most times -it will be enough to run -`nvim -l /path/to/nvim-treesitter/scripts/format-queries.lua /path/to/nvim-treesitter-textobjects/queries/`, -assuming you have an up-to-date version of the `nvim-treesitter` plugin. +To automatically format and check queries, run `make query` (Linux and macOS). diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..0f4ff572 --- /dev/null +++ b/Makefile @@ -0,0 +1,136 @@ +NVIM_VERSION ?= nightly +LUALS_VERSION := 3.14.0 + +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) + +LUALS := $(DEPDIR)/lua-language-server-$(LUALS_VERSION)-$(LUALS_ARCH) +LUALS_TARBALL := $(LUALS).tar.gz +LUALS_URL := https://github.com/LuaLS/lua-language-server/releases/download/$(LUALS_VERSION)/$(notdir $(LUALS_TARBALL)) + +.PHONY: luals +luals: $(LUALS) + +$(LUALS): + $(CURL) $(LUALS_URL) -o $(LUALS_TARBALL) + mkdir $@ + tar -xf $(LUALS_TARBALL) -C $@ + rm -rf $(LUALS_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) + +NVIM_TS := $(DEPDIR)/nvim-treesitter + +.PHONY: nvim_ts +nvim_ts: $(NVIM_TS) + +$(NVIM_TS): + git clone --filter=blob:none --single-branch https://github.com/nvim-treesitter/nvim-treesitter -b main $(NVIM_TS) + +PLENARY := $(DEPDIR)/plenary.nvim + +.PHONY: plenary +plenary: $(PLENARY) + +$(PLENARY): + git clone --filter=blob:none https://github.com/nvim-lua/plenary.nvim $(PLENARY) + +# actual test targets + +.PHONY: lua +lua: formatlua checklua + +.PHONY: formatlua +formatlua: $(STYLUA) + $(STYLUA)/stylua . + +.PHONY: checklua +checklua: $(LUALS) $(NVIM) + VIMRUNTIME=$(NVIM_RUNTIME) $(LUALS)/bin/lua-language-server \ + --configpath=../.luarc.json \ + --check=./ + +.PHONY: query +query: formatquery lintquery checkquery + +.PHONY: lintquery +lintquery: $(TSQUERYLS) + $(TSQUERYLS)/ts_query_ls lint queries + +.PHONY: formatquery +formatquery: $(TSQUERYLS) + $(TSQUERYLS)/ts_query_ls format queries + +.PHONY: checkquery +checkquery: $(TSQUERYLS) + $(TSQUERYLS)/ts_query_ls check queries + +.PHONY: docs +docs: $(NVIM) $(NVIM_TS) + NVIM_TS=$(NVIM_TS) $(NVIM_BIN) -l scripts/update-readme.lua + +.PHONY: tests +tests: $(NVIM) $(PLENARY) + PLENARY=$(PLENARY) $(NVIM_BIN) --headless --clean -u scripts/minimal_init.lua \ + -c "PlenaryBustedDirectory tests/$(TESTS) { minimal_init = './scripts/minimal_init.lua' }" + +.PHONY: all +all: lua query docs tests + +.PHONY: clean +clean: + rm -rf $(DEPDIR) diff --git a/README.md b/README.md index 44d8c3a3..30d287d4 100644 --- a/README.md +++ b/README.md @@ -12,21 +12,18 @@ You can install nvim-treesitter-textobjects with your favorite package manager, ### Using a package manager -If you are using [vim-plug](https://github.com/junegunn/vim-plug), put this in your init.vim file: +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'} Plug 'nvim-treesitter/nvim-treesitter-textobjects' ``` -If you are using [Packer](https://github.com/wbthomason/packer.nvim), put it in your init.lua file: +If you are using [lazy.nvim](https://github.com/folke/lazy.nvim), add this to your `init.lua` or `plugins.lua`. ```lua -use({ +{ "nvim-treesitter/nvim-treesitter-textobjects", - after = "nvim-treesitter", - requires = "nvim-treesitter/nvim-treesitter", -}) +} ``` ## Text objects: select @@ -35,52 +32,54 @@ Define your own text objects mappings similar to `ip` (inner paragraph) and `ap` (a paragraph). ```lua -lua <') or a table - -- mapping query_strings to modes. - selection_modes = { - ['@parameter.outer'] = 'v', -- charwise - ['@function.outer'] = 'V', -- linewise - ['@class.outer'] = '', -- blockwise - }, - -- If you set this to `true` (default is `false`) then any textobject is - -- extended to include preceding or succeeding whitespace. Succeeding - -- whitespace has priority in order to act similarly to eg the built-in - -- `ap`. - -- - -- Can also be a function which gets passed a table with the keys - -- * query_string: eg '@function.inner' - -- * selection_mode: eg 'v' - -- and should return true or false - include_surrounding_whitespace = true, +-- configuration +require("nvim-treesitter-textobjects").setup { + select = { + -- Automatically jump forward to textobj, similar to targets.vim + lookahead = true, + -- You can choose the select mode (default is charwise 'v') + -- + -- Can also be a function which gets passed a table with the keys + -- * query_string: eg '@function.inner' + -- * method: eg 'v' or 'o' + -- and should return the mode ('v', 'V', or '') or a table + -- mapping query_strings to modes. + selection_modes = { + ['@parameter.outer'] = 'v', -- charwise + ['@function.outer'] = 'V', -- linewise + ['@class.outer'] = '', -- blockwise }, + -- If you set this to `true` (default is `false`) then any textobject is + -- extended to include preceding or succeeding whitespace. Succeeding + -- whitespace has priority in order to act similarly to eg the built-in + -- `ap`. + -- + -- Can also be a function which gets passed a table with the keys + -- * query_string: eg '@function.inner' + -- * selection_mode: eg 'v' + -- and should return true of false + include_surrounding_whitespace = false, }, } -EOF + +-- keymaps +-- You can use the capture groups defined in `textobjects.scm` +vim.keymap.set({ "x", "o" }, "af", function() + require "nvim-treesitter-textobjects.select".select_textobject("@function.outer", "textobjects") +end) +vim.keymap.set({ "x", "o" }, "if", function() + require "nvim-treesitter-textobjects.select".select_textobject("@function.inner", "textobjects") +end) +vim.keymap.set({ "x", "o" }, "ac", function() + require "nvim-treesitter-textobjects.select".select_textobject("@class.outer", "textobjects") +end) +vim.keymap.set({ "x", "o" }, "ic", function() + require "nvim-treesitter-textobjects.select".select_textobject("@class.inner", "textobjects") +end) +-- You can also use captures from other query groups like `locals.scm` +vim.keymap.set({ "x", "o" }, "as", function() + require "nvim-treesitter-textobjects.select".select_textobject("@local.scope", "locals") +end) ``` ## Text objects: swap @@ -89,21 +88,13 @@ Define your own mappings to swap the node under the cursor with the next or prev like function parameters or arguments. ```lua -lua <a"] = "@parameter.inner", - }, - swap_previous = { - ["A"] = "@parameter.inner", - }, - }, - }, -} -EOF +-- keymaps +vim.keymap.set("n", "a", function() + require("nvim-treesitter-textobjects.swap").swap_next "@parameter.inner" +end) +vim.keymap.set("n", "A", function() + require("nvim-treesitter-textobjects.swap").swap_previous "@parameter.outer" +end) ``` ## Text objects: move @@ -113,56 +104,69 @@ This is similar to `]m`, `[m`, `]M`, `[M` Neovim's mappings to jump to the next or previous function. ```lua -lua </.scm file in your runtime path. - -- Below example nvim-treesitter's `locals.scm` and `folds.scm`. They also provide highlights.scm and indent.scm. - ["]s"] = { query = "@scope", query_group = "locals", desc = "Next scope" }, - ["]z"] = { query = "@fold", query_group = "folds", desc = "Next fold" }, - }, - goto_next_end = { - ["]M"] = "@function.outer", - ["]["] = "@class.outer", - }, - goto_previous_start = { - ["[m"] = "@function.outer", - ["[["] = "@class.outer", - }, - goto_previous_end = { - ["[M"] = "@function.outer", - ["[]"] = "@class.outer", - }, - -- Below will go to either the start or the end, whichever is closer. - -- Use if you want more granular movements - -- Make it even more gradual by adding multiple queries and regex. - goto_next = { - ["]d"] = "@conditional.outer", - }, - goto_previous = { - ["[d"] = "@conditional.outer", - } - }, +-- configuration +require("nvim-treesitter-textobjects").setup { + move = { + -- whether to set jumps in the jumplist + set_jumps = true, }, } -EOF + +-- keymaps +-- You can use the capture groups defined in `textobjects.scm` +vim.keymap.set({ "n", "x", "o" }, "]m", function() + require("nvim-treesitter-textobjects.move").goto_next_start("@function.outer", "textobjects") +end) +vim.keymap.set({ "n", "x", "o" }, "]]", function() + require("nvim-treesitter-textobjects.move").goto_next_start("@class.outer", "textobjects") +end) +-- You can also pass a list to group multiple queries. +vim.keymap.set({ "n", "x", "o" }, "]o", function() + move.goto_next_start({"@loop.inner", "@loop.outer"}, "textobjects") +end) +-- You can also use captures from other query groups like `locals.scm` or `folds.scm` +vim.keymap.set({ "n", "x", "o" }, "]s", function() + require("nvim-treesitter-textobjects.move").goto_next_start("@local.scope", "locals") +end) +vim.keymap.set({ "n", "x", "o" }, "]z", function() + require("nvim-treesitter-textobjects.move").goto_next_start("@fold", "folds") +end) + +vim.keymap.set({ "n", "x", "o" }, "]M", function() + require("nvim-treesitter-textobjects.move").goto_next_end("@function.outer", "textobjects") +end) +vim.keymap.set({ "n", "x", "o" }, "][", function() + require("nvim-treesitter-textobjects.move").goto_next_end("@class.outer", "textobjects") +end) + +vim.keymap.set({ "n", "x", "o" }, "[m", function() + require("nvim-treesitter-textobjects.move").goto_previous_start("@function.outer", "textobjects") +end) +vim.keymap.set({ "n", "x", "o" }, "[[", function() + require("nvim-treesitter-textobjects.move").goto_previous_start("@class.outer", "textobjects") +end) + +vim.keymap.set({ "n", "x", "o" }, "[M", function() + require("nvim-treesitter-textobjects.move").goto_previous_end("@function.outer", "textobjects") +end) +vim.keymap.set({ "n", "x", "o" }, "[]", function() + require("nvim-treesitter-textobjects.move").goto_previous_end("@class.outer", "textobjects") +end) + +-- Go to either the start or the end, whichever is closer. +-- Use if you want more granular movements +vim.keymap.set({ "n", "x", "o" }, "]d", function() + require("nvim-treesitter-textobjects.move").goto_next("@conditional.outer", "textobjects") +end) +vim.keymap.set({ "n", "x", "o" }, "[d", function() + require("nvim-treesitter-textobjects.move").goto_previous("@conditional.outer", "textobjects") +end) ``` You can make the movements repeatable like `;` and `,`. ```lua -local ts_repeat_move = require "nvim-treesitter.textobjects.repeatable_move" +local ts_repeat_move = require "nvim-treesitter-textobjects.repeatable_move" -- Repeat movement with ; and , -- ensure ; goes forward and , goes backward regardless of the last direction @@ -194,89 +198,42 @@ vim.keymap.set({ "n", "x", "o" }, "", function() end) ``` -Furthermore, you can make any custom movements (e.g. from another plugin) repeatable with the same keys. -This doesn't need to be treesitter-related. - -```lua --- example: make gitsigns.nvim movement repeatable with ; and , keys. -local gs = require("gitsigns") - --- make sure forward function comes first -local next_hunk_repeat, prev_hunk_repeat = ts_repeat_move.make_repeatable_move_pair(gs.next_hunk, gs.prev_hunk) --- Or, use `make_repeatable_move` or `set_last_move` functions for more control. See the code for instructions. - -vim.keymap.set({ "n", "x", "o" }, "]h", next_hunk_repeat) -vim.keymap.set({ "n", "x", "o" }, "[h", prev_hunk_repeat) -``` - -Alternative way is to use a repeatable movement managing plugin such as [nvim-next](https://github.com/ghostbuster91/nvim-next). - -## Textobjects: LSP interop - -- peek_definition_code: show textobject surrounding definition as determined - using Neovim's built-in LSP in a floating window. Press the shortcut twice - to enter the floating window. - -```lua -lua <df"] = "@function.outer", - ["dF"] = "@class.outer", - }, - }, - }, -} -EOF -``` +For a similar way of making arbitrary movements repeatable, see [nvim-next](https://github.com/ghostbuster91/nvim-next). # Overriding or extending textobjects Textobjects are defined in the `textobjects.scm` files. You can extend or override those files by following the instructions at . + You can also use a custom capture for your own textobjects, and use it in any of the textobject modules, for example: -```scm --- after/queries/python/textobjects.scm -; extends +```query +; queries/python/textobjects.scm +;; extends (function_definition) @custom_capture ``` ```lua -lua < dockerfile 🟩 +ecma🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 + elixir 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 elm 🟩 🟩 🟩 🟩 🟩 🟩 🟩 @@ -350,6 +309,10 @@ Here are some rules about the query names that should be noted. foam 🟩 🟩 🟩 🟩 🟩 🟩 🟩 +gdscript 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 + +glimmer 🟩 🟩 🟩 🟩 🟩 🟩 🟩 + glsl🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 go🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 @@ -372,6 +335,8 @@ Here are some rules about the query names that should be noted. javascript🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 +jsx🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 + julia🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 kotlin 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 @@ -380,6 +345,8 @@ Here are some rules about the query names that should be noted. lua🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 +markdown 🟩 🟩 🟩 🟩 + matlab 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 nasm 🟩 🟩 🟩 🟩 🟩 🟩 @@ -395,11 +362,14 @@ Here are some rules about the query names that should be noted. php 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 php_only 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 +prisma 🟩 🟩 🟩 🟩 🟩 🟩 python🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 ql 🟩 🟩 🟩 🟩 🟩 +query 🟩 🟩 🟩 🟩 + r🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 🟩 readline 🟩 🟩 🟩 🟩 🟩 🟩 diff --git a/autoload/nvim_treesitter_textobjects.vim b/autoload/nvim_treesitter_textobjects.vim deleted file mode 100644 index c39c6a69..00000000 --- a/autoload/nvim_treesitter_textobjects.vim +++ /dev/null @@ -1,3 +0,0 @@ -function! nvim_treesitter_textobjects#available_textobjects(arglead, cmdline, cursorpos) abort - return join(luaeval("vim.tbl_map(function(o) return '@'..o end, require'nvim-treesitter.textobjects.shared'.available_textobjects())"), "\n") -endfunction diff --git a/doc/nvim-treesitter-textobjects.txt b/doc/nvim-treesitter-textobjects.txt index ea31b557..6b3b8ec3 100644 --- a/doc/nvim-treesitter-textobjects.txt +++ b/doc/nvim-treesitter-textobjects.txt @@ -16,11 +16,7 @@ similar to `ip` (inner paragraph) and `ap` (a paragraph). Query files: `textobjects.scm`. Supported options: -- enable: `true` or `false`. -- disable: list of languages. - lookahead: `true` or `false`, whether or not to look ahead for the textobject -- keymaps: map of keymaps to a tree-sitter query - (`(function_definition) @function`) or capture group (`@function.inner`). - selection_modes: map of capture group to `v`(charwise), `V`(linewise), or ``(blockwise), choose a selection mode per capture, default is `v`(charwise). - include_surrounding_whitespace: `true` or `false`, when `true` textobjects @@ -29,39 +25,55 @@ Supported options: `query_string` (`@function.inner`) and `selection_mode` (`v`) and returns `true` of `false`. -> - lua <lua + -- configuration + require("nvim-treesitter-textobjects").setup { + select = { + -- Automatically jump forward to textobj, similar to targets.vim + lookahead = true, + -- You can choose the select mode (default is charwise 'v') + -- + -- Can also be a function which gets passed a table with the keys + -- * query_string: eg '@function.inner' + -- * method: eg 'v' or 'o' + -- and should return the mode ('v', 'V', or '') or a table + -- mapping query_strings to modes. + selection_modes = { + ['@parameter.outer'] = 'v', -- charwise + ['@function.outer'] = 'V', -- linewise + ['@class.outer'] = '', -- blockwise }, }, + -- If you set this to `true` (default is `false`) then any textobject is + -- extended to include preceding or succeeding whitespace. Succeeding + -- whitespace has priority in order to act similarly to eg the built-in + -- `ap`. + -- + -- Can also be a function which gets passed a table with the keys + -- * query_string: eg '@function.inner' + -- * selection_mode: eg 'v' + -- and should return true of false + include_surrounding_whitespace = false, } - EOF + + -- keymaps + -- You can use the capture groups defined in `textobjects.scm` + vim.keymap.set({ "x", "o" }, "af", function() + require "nvim-treesitter-textobjects.select".select_textobject("@function.outer", "textobjects") + end) + vim.keymap.set({ "x", "o" }, "if", function() + require "nvim-treesitter-textobjects.select".select_textobject("@function.inner", "textobjects") + end) + vim.keymap.set({ "x", "o" }, "ac", function() + require "nvim-treesitter-textobjects.select".select_textobject("@class.outer", "textobjects") + end) + vim.keymap.set({ "x", "o" }, "ic", function() + require "nvim-treesitter-textobjects.select".select_textobject("@class.inner", "textobjects") + end) + -- You can also use captures from other query groups like `locals.scm` + vim.keymap.set({ "x", "o" }, "as", function() + require "nvim-treesitter-textobjects.select".select_textobject("@local.scope", "locals") + end) < ------------------------------------------------------------------------------ @@ -72,29 +84,14 @@ Define your own mappings to swap the node under the cursor with the next or prev like function parameters or arguments. Query files: `textobjects.scm`. -Supported options: -- enable: `true` or `false`. -- disable: list of languages. -- swap_next: map of keymaps to a list of tree-sitter capture groups (`{@parameter.inner}`). Capture groups that come earlier in the list are preferred. -- swap_previous: same as swap_next, but it will swap with the previous text - object. - -> - lua <a"] = "@parameter.inner", - }, - swap_previous = { - ["A"] = "@parameter.inner", - }, - }, - }, - } - EOF + +>lua + vim.keymap.set("n", "a", function() + require("nvim-treesitter-textobjects.swap").swap_next "@parameter.inner" + end) + vim.keymap.set("n", "A", function() + require("nvim-treesitter-textobjects.swap").swap_next "@parameter.outer" + end) < ------------------------------------------------------------------------------ @@ -107,77 +104,68 @@ or previous function. Query files: `textobjects.scm`. Supported options: -- enable: `true` or `false`. -- disable: list of languages. - set_jumps: whether to set jumps in the jumplist -- goto_next_start: map of keymaps to a list of tree-sitter capture groups (`{@function.outer, @class.outer}`). - The one that starts closest to the cursor will be chosen, preferring row-proximity to column-proximity. -- goto_next_end: same as goto_next_start, but it jumps to the start of - the text object. -- goto_previous_start: same as goto_next_start, but it jumps to the previous - text object. -- goto_previous_end: same as goto_next_end, but it jumps to the previous - text object. - -> - lua < - lua <df"] = "@function.outer", - ["dF"] = "@class.outer", - }, - }, +>lua + -- configuration + require("nvim-treesitter-textobjects").setup { + move = { + -- whether to set jumps in the jumplist + set_jumps = true, }, } - EOF + + -- keymaps + -- You can use the capture groups defined in `textobjects.scm` + vim.keymap.set({ "n", "x", "o" }, "]m", function() + require("nvim-treesitter-textobjects.move").goto_next_start("@function.outer", "textobjects") + end) + vim.keymap.set({ "n", "x", "o" }, "]]", function() + require("nvim-treesitter-textobjects.move").goto_next_start("@class.outer", "textobjects") + end) + -- You can also pass a list to group multiple queries. + vim.keymap.set({ "n", "x", "o" }, "]o", function() + move.goto_next_start({"@loop.inner", "@loop.outer"}, "textobjects") + end) + -- You can also use captures from other query groups like `locals.scm` or `folds.scm` + vim.keymap.set({ "n", "x", "o" }, "]s", function() + require("nvim-treesitter-textobjects.move").goto_next_start("@local.scope", "locals") + end) + vim.keymap.set({ "n", "x", "o" }, "]z", function() + require("nvim-treesitter-textobjects.move").goto_next_start("@fold", "folds") + end) + + vim.keymap.set({ "n", "x", "o" }, "]M", function() + require("nvim-treesitter-textobjects.move").goto_next_end("@function.outer", "textobjects") + end) + vim.keymap.set({ "n", "x", "o" }, "][", function() + require("nvim-treesitter-textobjects.move").goto_next_end("@class.outer", "textobjects") + end) + + vim.keymap.set({ "n", "x", "o" }, "[m", function() + require("nvim-treesitter-textobjects.move").goto_previous_start("@function.outer", "textobjects") + end) + vim.keymap.set({ "n", "x", "o" }, "[[", function() + require("nvim-treesitter-textobjects.move").goto_previous_start("@class.outer", "textobjects") + end) + + vim.keymap.set({ "n", "x", "o" }, "[M", function() + require("nvim-treesitter-textobjects.move").goto_previous_end("@function.outer", "textobjects") + end) + vim.keymap.set({ "n", "x", "o" }, "[]", function() + require("nvim-treesitter-textobjects.move").goto_previous_end("@class.outer", "textobjects") + end) + + -- Go to either the start or the end, whichever is closer. + -- Use if you want more granular movements + vim.keymap.set({ "n", "x", "o" }, "]d", function() + require("nvim-treesitter-textobjects.move").goto_next("@conditional.outer", "textobjects") + end) + vim.keymap.set({ "n", "x", "o" }, "[d", function() + require("nvim-treesitter-textobjects.move").goto_previous("@conditional.outer", "textobjects") + end) < + ------------------------------------------------------------------------------ *nvim-treesitter-text-objects-override* Overrriding or extending text objects~ @@ -185,35 +173,22 @@ Overrriding or extending text objects~ Textobjects are defined in the `textobjects.scm` files. You can extend or override those files by following the instructions at -. +https://github.com/nvim-treesitter/nvim-treesitter#adding-queries. You can also use a custom capture for your own textobjects, and use it in any of the textobject modules, for example: -> - lua <lua + for _, mode in ipairs { "x", "o" } do + vim.keymap.set(mode, "aF", function() + select.select_textobject("@custom_capture", "textobjects", mode) + end) + end < -Where '@custom-capture' can be defined in a scheme file -> - ```scm - -- after/queries/python/textobjects.scm - (function_definition) @custom-capture - ``` +Where '@custom-capture' can be defined in a query file +>query + ; queries/python/textobjects.scm + ;; extends + (function_definition) @custom_capture < vim:tw=78:ts=8:expandtab:noet:ft=help:norl: diff --git a/lua/nvim-treesitter-textobjects.lua b/lua/nvim-treesitter-textobjects.lua deleted file mode 100644 index eaba6909..00000000 --- a/lua/nvim-treesitter-textobjects.lua +++ /dev/null @@ -1,74 +0,0 @@ -local configs = require "nvim-treesitter.configs" -local utils = require "nvim-treesitter.utils" -local ts = require "nvim-treesitter.compat" - -local M = {} - -M.has_textobjects = function(lang) - return ts.get_query_files(lang, "textobjects") ~= nil -end - -local function has_some_textobject_mapping(lang) - for _, v in pairs(configs.get_module("textobjects.select").keymaps) do - if type(v) == "table" then - if v[lang] then - return true - end - end - end - return false -end - -function M.init() - require("nvim-treesitter").define_modules { - textobjects = { - select = { - module_path = "nvim-treesitter.textobjects.select", - enable = false, - disable = {}, - is_supported = function(lang) - return M.has_textobjects(lang) or has_some_textobject_mapping(lang) - end, - lookahead = false, - lookbehind = false, - keymaps = {}, - selection_modes = {}, - }, - move = { - module_path = "nvim-treesitter.textobjects.move", - enable = false, - disable = {}, - is_supported = M.has_textobjects, - set_jumps = true, - goto_next_start = {}, - goto_next_end = {}, - goto_previous_start = {}, - goto_previous_end = {}, - goto_next = {}, - goto_previous = {}, - }, - swap = { - module_path = "nvim-treesitter.textobjects.swap", - enable = false, - disable = {}, - is_supported = M.has_textobjects, - swap_next = {}, - swap_previous = {}, - }, - lsp_interop = { - module_path = "nvim-treesitter.textobjects.lsp_interop", - enable = false, - border = "none", - floating_preview_opts = {}, - disable = {}, - is_supported = M.has_textobjects, - peek_definition_code = {}, - }, - }, - } - for _, m in ipairs { "select", "move", "repeatable_move", "swap", "lsp_interop" } do - utils.setup_commands("textobjects." .. m, require("nvim-treesitter.textobjects." .. m).commands) - end -end - -return M diff --git a/lua/nvim-treesitter-textobjects/config.lua b/lua/nvim-treesitter-textobjects/config.lua new file mode 100644 index 00000000..6c7fef07 --- /dev/null +++ b/lua/nvim-treesitter-textobjects/config.lua @@ -0,0 +1,54 @@ +---@alias TSTextObjects.SelectionMode 'v'|'V'|'' + +---@alias TSTextObjects.ConfigFunctionArgs {query_string: string, method: TSTextObjects.Method} + +---@class (exact) TSTextObjects.Config.Select +---@field lookahead? boolean +---@field lookbehind? boolean +---@field selection_modes? table|fun(opts: TSTextObjects.ConfigFunctionArgs): TSTextObjects.SelectionMode|table +---@field include_surrounding_whitespace? boolean|fun(opts: TSTextObjects.ConfigFunctionArgs): boolean + +---@class (exact) TSTextObjects.Config.Move +---@field set_jumps? boolean + +---@class (exact) TSTextObjects.Config.LspInterop +---@field floating_preview_opts? table + +---@class (exact) TSTextObjects.Config +---@field select TSTextObjects.Config.Select +---@field move TSTextObjects.Config.Move + +---@class (exact) TSTextObjects.UserConfig : TSTextObjects.Config +---@field select? TSTextObjects.Config.Select +---@field move? TSTextObjects.Config.Move + +---@type TSTextObjects.Config +local default_config = { + select = { + lookahead = false, + lookbehind = false, + selection_modes = {}, + include_surrounding_whitespace = false, + }, + move = { + set_jumps = true, + }, +} + +local config = vim.deepcopy(default_config) + +local M = {} + +---@param cfg TSTextObjects.UserConfig +function M.update(cfg) + config = vim.tbl_deep_extend('force', config, cfg) +end + +---@cast M +TSTextObjects.Config +setmetatable(M, { + __index = function(_, k) + return config[k] + end, +}) + +return M diff --git a/lua/nvim-treesitter-textobjects/init.lua b/lua/nvim-treesitter-textobjects/init.lua new file mode 100644 index 00000000..d34e9d6d --- /dev/null +++ b/lua/nvim-treesitter-textobjects/init.lua @@ -0,0 +1,10 @@ +local M = {} + +---@param options TSTextObjects.UserConfig? +function M.setup(options) + if options then + require('nvim-treesitter-textobjects.config').update(options) + end +end + +return M diff --git a/lua/nvim-treesitter-textobjects/move.lua b/lua/nvim-treesitter-textobjects/move.lua new file mode 100644 index 00000000..ef4a9b62 --- /dev/null +++ b/lua/nvim-treesitter-textobjects/move.lua @@ -0,0 +1,198 @@ +local api = vim.api + +local shared = require('nvim-treesitter-textobjects.shared') +local repeatable_move = require('nvim-treesitter-textobjects.repeatable_move') +local global_config = require('nvim-treesitter-textobjects.config') + +---@param range Range4? +---@param goto_end boolean +---@param avoid_set_jump boolean +local function goto_node(range, goto_end, avoid_set_jump) + if not range then + return + end + + if not avoid_set_jump then + vim.cmd("normal! m'") + end + ---@type integer, integer, integer, integer + local start_row, start_col, end_row, end_col = unpack(range) + + -- Enter visual mode if we are in operator pending mode + -- If we don't do this, it will miss the last character. + local mode = api.nvim_get_mode() + if mode.mode == 'no' then + vim.cmd('normal! v') + end + + -- Position is 1, 0 indexed. + if not goto_end then + api.nvim_win_set_cursor(0, { start_row + 1, start_col }) + else + api.nvim_win_set_cursor(0, { end_row + 1, end_col - 1 }) + end +end + +local M = {} + +---@param opts TSTextObjects.MoveOpts +---@param query_strings string[]|string +---@param query_group? string +local function move(opts, query_strings, query_group) + query_group = query_group or 'textobjects' + if type(query_strings) == 'string' then + query_strings = { query_strings } + end + + local winid = api.nvim_get_current_win() + local bufnr = api.nvim_win_get_buf(winid) + + local forward = opts.forward + local starts ---@type {[1]: boolean, [2]: boolean} + if opts.start == nil then + starts = { true, false } + else + if opts.start then + starts = { true } + else + starts = { false } + end + end + + local config = global_config.move + + -- score is a byte position. + --- + ---@param start_ boolean + ---@param range Range6 + ---@return integer + local function scoring_function(start_, range) + local score ---@type integer + if start_ then + score = range[3] + else + score = range[6] + end + if forward then + return -score + else + return score + end + end + + ---@param start_ boolean + ---@param range Range6 + ---@return boolean + local function filter_function(start_, range) + local row, col = unpack(api.nvim_win_get_cursor(winid)) --[[@as integer, integer]] + row = row - 1 -- nvim_win_get_cursor is (1,0)-indexed + ---@type integer, integer, integer, integer, integer, integer + local start_row, start_col, _, end_row, end_col, _ = unpack(range) + + if not start_ then + if end_col == 0 then + start_row = end_row - 1 + start_col = end_col + else + start_row = end_row + start_col = end_col - 1 ---@type integer + end + end + if forward then + return start_row > row or (start_row == row and start_col > col) + else + return start_row < row or (start_row == row and start_col < col) + end + end + + for _ = 1, vim.v.count1 do + local best_range ---@type Range6? + local best_score ---@type integer + local best_start ---@type boolean + for _, query_string in ipairs(query_strings) do + for _, start_ in ipairs(starts) do + local current_range = shared.find_best_range( + bufnr, + query_string, + query_group, + function(range) + return filter_function(start_, range) + end, + function(range) + return scoring_function(start_, range) + end + ) + + if current_range then + local score = scoring_function(start_, current_range) + if not best_range then + best_range = current_range + best_score = score + best_start = start_ + end + if score > best_score then + best_range = current_range + best_score = score + best_start = start_ + end + end + end + end + goto_node(best_range and shared.torange4(best_range), not best_start, not config.set_jumps) + end +end + +---@type fun(opts: TSTextObjects.MoveOpts, query_strings: string[]|string, query_group?: string) +local move_repeatable = repeatable_move.make_repeatable_move(move) + +---@param query_strings string|string[] +---@param query_group? string +M.goto_next_start = function(query_strings, query_group) + move_repeatable({ + forward = true, + start = true, + }, query_strings, query_group) +end +---@param query_strings string|string[] +---@param query_group? string +M.goto_next_end = function(query_strings, query_group) + move_repeatable({ + forward = true, + start = false, + }, query_strings, query_group) +end +---@param query_strings string|string[] +---@param query_group? string +M.goto_previous_start = function(query_strings, query_group) + move_repeatable({ + forward = false, + start = true, + }, query_strings, query_group) +end +---@param query_strings string|string[] +---@param query_group? string +M.goto_previous_end = function(query_strings, query_group) + move_repeatable({ + forward = false, + start = false, + }, query_strings, query_group) +end + +---@param query_strings string|string[] +---@param query_group? string +M.goto_next = function(query_strings, query_group) + move_repeatable({ + forward = true, + }, query_strings, query_group) +end +---@param query_strings string|string[] +---@param query_group? string +M.goto_previous = function(query_strings, query_group) + move_repeatable({ + forward = false, + query_strings = query_strings, + query_group = query_group, + }, query_strings, query_group) +end + +return M diff --git a/lua/nvim-treesitter-textobjects/repeatable_move.lua b/lua/nvim-treesitter-textobjects/repeatable_move.lua new file mode 100644 index 00000000..06437f62 --- /dev/null +++ b/lua/nvim-treesitter-textobjects/repeatable_move.lua @@ -0,0 +1,97 @@ +local M = {} + +---@class TSTextObjects.MoveOpts +---@field forward boolean If true, move forward, and false is for backward. +---@field start? boolean If true, choose the start of the node, and false is for the end. + +---@alias TSTextObjects.MoveFunction fun(opts: TSTextObjects.MoveOpts, ...: any) + +---@class TSTextObjects.RepeatableMove +---@field func string | TSTextObjects.MoveFunction +---@field opts TSTextObjects.MoveOpts +---@field additional_args table + +---@type TSTextObjects.RepeatableMove +M.last_move = nil + +--- Make move function repeatable. Creates a wrapper that takes a TSTextObjects.MoveOpts table, +--- stores them, and executes the move. +--- +---@param move_fn TSTextObjects.MoveFunction +---@return TSTextObjects.MoveFunction +M.make_repeatable_move = function(move_fn) + return function(opts, ...) + M.last_move = { func = move_fn, opts = vim.deepcopy(opts), additional_args = { ... } } + move_fn(opts, ...) + end +end + +---@param opts_extend TSTextObjects.MoveOpts? +M.repeat_last_move = function(opts_extend) + if not M.last_move then + return + end + local opts = vim.tbl_deep_extend('force', M.last_move.opts, opts_extend or {}) + if M.last_move.func == 'f' or M.last_move.func == 't' then + vim.cmd([[normal! ]] .. vim.v.count1 .. (opts.forward and ';' or ',')) + elseif M.last_move.func == 'F' or M.last_move.func == 'T' then + vim.cmd([[normal! ]] .. vim.v.count1 .. (opts.forward and ',' or ';')) + else + M.last_move.func(opts, unpack(M.last_move.additional_args)) + end +end + +M.repeat_last_move_opposite = function() + return M.last_move and M.repeat_last_move({ forward = not M.last_move.opts.forward }) +end + +M.repeat_last_move_next = function() + return M.repeat_last_move({ forward = true }) +end + +M.repeat_last_move_previous = function() + return M.repeat_last_move({ forward = false }) +end + +-- NOTE: map builtin_f_expr, builtin_F_expr, builtin_t_expr, builtin_T_expr with { expr = true }. +-- +-- We are not using M.make_repeatable_move or M.set_last_move and instead registering at M.last_move manually +-- because move_fn is not a function (but string f, F, t, T). +-- We don't want to execute a move function, but instead return an expression (f, F, t, T). +M.builtin_f_expr = function() + M.last_move = { + func = 'f', + opts = { forward = true }, + additional_args = {}, + } + return 'f' +end + +M.builtin_F_expr = function() + M.last_move = { + func = 'F', + opts = { forward = false }, + additional_args = {}, + } + return 'F' +end + +M.builtin_t_expr = function() + M.last_move = { + func = 't', + opts = { forward = true }, + additional_args = {}, + } + return 't' +end + +M.builtin_T_expr = function() + M.last_move = { + func = 'T', + opts = { forward = false }, + additional_args = {}, + } + return 'T' +end + +return M diff --git a/lua/nvim-treesitter-textobjects/select.lua b/lua/nvim-treesitter-textobjects/select.lua new file mode 100644 index 00000000..713c2cb1 --- /dev/null +++ b/lua/nvim-treesitter-textobjects/select.lua @@ -0,0 +1,224 @@ +local api = vim.api +local global_config = require('nvim-treesitter-textobjects.config') +local shared = require('nvim-treesitter-textobjects.shared') + +---@param range Range4 +---@param selection_mode TSTextObjects.SelectionMode +local function update_selection(range, selection_mode) + ---@type integer, integer, integer, integer + local start_row, start_col, end_row, end_col = unpack(range) + selection_mode = selection_mode or 'v' + + -- 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 = api.nvim_replace_termcodes(selection_mode, true, true, true) + vim.cmd.normal({ selection_mode, bang = true }) + end + + local end_col_offset = 1 + + if selection_mode == 'v' and vim.o.selection == 'exclusive' then + end_col_offset = 0 + end + + -- Position is 1, 0 indexed. + api.nvim_win_set_cursor(0, { start_row + 1, start_col }) + vim.cmd('normal! o') + api.nvim_win_set_cursor(0, { end_row + 1, end_col - end_col_offset }) +end + +local M = {} + +---@param bufnr integer +---@param row integer +---@param col integer +---@return string? +local function char_at_position(bufnr, row, col) + local ok, char = pcall(api.nvim_buf_get_text, bufnr, row, col, row, col + 1, {}) + if ok then + return char[1] + end +end + +---@param bufnr integer +---@param row integer +---@param col integer +---@return boolean +local function is_whitespace(bufnr, row, col) + local char = char_at_position(bufnr, row, col) + if char == nil then + return false + end + if char == '' then + return true + end + return string.match(char, '%s') +end + +---@param bufnr integer +---@param row integer +---@param col integer +---@return { [1]: integer, [2]: integer }? position +local function next_position(bufnr, row, col) + local max_col = #vim.fn.getbufoneline(bufnr, row + 1) - 1 + local max_row = api.nvim_buf_line_count(bufnr) - 1 + if col >= max_col then + if row >= max_row then + return nil + end + row = row + 1 + col = 0 + else + col = col + 1 + end + return { row, col } +end + +---@param bufnr integer +---@param row integer +---@param col integer +---@return { [1]: integer, [2]: integer }? position +local function previous_position(bufnr, row, col) + if col <= 0 then + if row <= 0 then + return nil + end + row = row - 1 + -- Empty line should be considered as a single character + col = math.max(#vim.fn.getbufoneline(bufnr, row + 1) - 1, 0) + else + col = col - 1 + end + return { row, col } +end + +---@param bufnr integer +---@param range Range4 +---@param selection_mode string +---@return Range4? +local function include_surrounding_whitespace(bufnr, range, selection_mode) + local start_row, start_col, end_row, end_col = unpack(range) ---@type integer, integer, integer, integer + local extended = false + local position = { end_row, end_col - 1 } + local next = next_position(bufnr, unpack(position)) + while next and is_whitespace(bufnr, unpack(next)) do + extended = true + position = next ---@type {[1]: integer, [2]: integer} + next = next_position(bufnr, unpack(position)) + end + if extended then + -- don't extend in both directions + return { start_row, start_col, position[1], position[2] + 1 } + end + + position = { start_row, start_col } + local previous = previous_position(bufnr, unpack(position)) + + while previous and is_whitespace(bufnr, unpack(previous)) do + position = previous + previous = previous_position(bufnr, unpack(position)) + end + if selection_mode == 'linewise' then + position = assert(next_position(bufnr, unpack(position))) + end + return { position[1], position[2], end_row, end_col } +end + +---@generic T +---@param val `T`|fun(opts: table):`T` +---@param opts table +---@return T +local function_or_value_to_value = function(val, opts) + if type(val) == 'function' then + return val(opts) + else + return val + end +end + +---@param query_string string +---@param query_group? string +function M.select_textobject(query_string, query_group) + query_group = query_group or 'textobjects' + local bufnr = vim.api.nvim_get_current_buf() + + local config = global_config.select + local lookahead = config.lookahead + local lookbehind = config.lookbehind + local surrounding_whitespace = config.include_surrounding_whitespace + local range6 = shared.textobject_at_point( + query_string, + query_group, + bufnr, + nil, + { lookahead = lookahead, lookbehind = lookbehind } + ) + if range6 then + local range4 = shared.torange4(range6) + local selection_mode = M.detect_selection_mode(query_string) + if + function_or_value_to_value(surrounding_whitespace, { + query_string = query_string, + selection_mode = selection_mode, + }) + then + ---@diagnostic disable-next-line: cast-local-type + range4 = include_surrounding_whitespace(bufnr, range4, selection_mode) + end + if range4 then + update_selection(range4, selection_mode) + end + end +end + +---@alias TSTextObjects.Method "operator-pending" | "visual" +---@alias TSTextObjects.Mode "nov" | "noV" | "no\22" | "v" | "V" | "\22" + +---@param query_string string +---@return TSTextObjects.SelectionMode +function M.detect_selection_mode(query_string) + -- Update selection mode with different methods based on keymapping mode + ---@type table + local keymap_to_method = { + nov = 'operator-pending', + noV = 'operator-pending', + ['no\22'] = 'operator-pending', -- \22 is the scape sequence of + V = 'visual', + v = 'visual', + ['\22'] = 'visual', -- \22 is the scape sequence of + } + local method = keymap_to_method[api.nvim_get_mode().mode] + + local config = global_config.select + local selection_modes = function_or_value_to_value(config.selection_modes, { + query_string = query_string, + method = method, + }) --[[@as TSTextObjects.SelectionMode|table]] + local selection_mode ---@type TSTextObjects.SelectionMode + if type(selection_modes) == 'table' then + selection_mode = selection_modes[query_string] or 'v' + else + selection_mode = selection_modes or 'v' + end + + local ret_value = selection_mode + local mode = api.nvim_get_mode().mode + + local is_normal_or_charwise_v = mode == 'n' or mode == 'v' + if not is_normal_or_charwise_v then + -- According to "mode()" mapping, if we are in operator pending mode or visual mode, + -- then last char is {v,V,}, exept for "no", which is "o", in which case we honor + -- last set `selection_mode` + mode = mode:sub(#mode) --[[@as string]] + ret_value = mode == 'o' and selection_mode or mode + end + + return ret_value == 'n' and 'v' or ret_value +end + +return M diff --git a/lua/nvim-treesitter-textobjects/shared.lua b/lua/nvim-treesitter-textobjects/shared.lua new file mode 100644 index 00000000..15099ffe --- /dev/null +++ b/lua/nvim-treesitter-textobjects/shared.lua @@ -0,0 +1,469 @@ +local ts = vim.treesitter +local add_bytes = require('vim.treesitter._range').add_bytes + +-- lookup table for parserless queries +local lang_to_parser = { ecma = 'javascript', jsx = 'javascript' } + +---@alias TSTextObjects.Metadata {range: {[1]: number, [2]: number, [3]: number, [4]: number, [5]: number, [6]: number, [7]: string}} + +local M = {} + +---@param object table +---@param path string[] +---@param value table +local function insert_to_path(object, path, value) + ---@type table> + local curr_obj = object + + for index = 1, (#path - 1) do + if curr_obj[path[index]] == nil then + curr_obj[path[index]] = {} + end + + ---@type table> + curr_obj = curr_obj[path[index]] + end + + ---@type table> + curr_obj[path[#path]] = value +end + +---Memoize a function using hash_fn to hash the arguments. +---@generic F: function +---@param fn F +---@param hash_fn fun(...): any +---@return F +local function memoize(fn, hash_fn) + local cache = setmetatable({}, { __mode = 'kv' }) ---@type table + + return function(...) + local key = hash_fn(...) + if cache[key] == nil then + local v = fn(...) ---@type any + cache[key] = v ~= nil and v or vim.NIL + end + + local v = cache[key] + return v ~= vim.NIL and v or nil + end +end + +--- Prepare matches for given query_group and parsed tree +--- memoize by buffer tick and query group +--- +---@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 +---@return table[] +local get_query_matches = memoize(function(bufnr, query_group, root, root_lang) + local query = ts.query.get(root_lang, query_group) + if not query then + return {} + end + + local matches = {} ---@type table[] + local start_row, _, end_row, _ = root:range() + -- The end row is exclusive so we need to add 1 to it. + for pattern, match, metadata in query:iter_matches(root, bufnr, start_row, end_row + 1) do + if pattern then + local prepared_match = {} + + -- Extract capture names from each match + for id, nodes in pairs(match) do + local query_name = query.captures[id] -- name of the capture in the query + if query_name ~= nil then + local path = vim.split(query_name, '%.') + if metadata[id] and metadata[id].range then + insert_to_path(prepared_match, path, add_bytes(bufnr, metadata[id].range)) + else + local srow, scol, sbyte, erow, ecol, ebyte = nodes[1]:range(true) + if #nodes > 1 then + local _, _, _, e_erow, e_ecol, e_ebyte = nodes[#nodes]:range(true) + erow = e_erow + ecol = e_ecol + ebyte = e_ebyte + end + insert_to_path(prepared_match, path, { srow, scol, sbyte, erow, ecol, ebyte }) + end + end + end + + if metadata.range and metadata.range[7] then + ---@cast metadata TSTextObjects.Metadata + local query_name = metadata.range[7] + local path = vim.split(query_name, '%.') + insert_to_path(prepared_match, path, { + metadata.range[1], + metadata.range[2], + metadata.range[3], + metadata.range[4], + metadata.range[5], + metadata.range[6], + }) + end + + matches[#matches + 1] = prepared_match + end + end + return matches +end, function(bufnr, query_group, root) + return string.format('%d-%s-%s', bufnr, root:id(), query_group) +end) + +---@param tbl table> the table to access +---@param path string the '.' separated path +---@return any|nil result the value at path or nil +local function get_at_path(tbl, path) + if path == '' then + return tbl + end + + local segments = vim.split(path, '%.') + local result = tbl + + for _, segment in ipairs(segments) do + if type(result) == 'table' then + ---@type any + result = result[segment] + end + end + + return result +end + +-- TODO(clason): memoize? +---@param bufnr integer +---@param query_string string +---@param query_group string +---@return Range6[] +local function get_capture_ranges_recursively(bufnr, query_string, query_group) + if query_string:sub(1, 1) ~= '@' then + error('Captures must start with "@"') + return {} + end + query_string = query_string:sub(2) + + local parser = ts.get_parser(bufnr) + if not parser then + return {} + end + + local ranges = {} ---@type Range6[] + parser:for_each_tree(function(tree, lang_tree) + local tree_lang = lang_tree:lang() + + local matches = get_query_matches(bufnr, query_group, tree:root(), tree_lang) + for _, match in pairs(matches) do + local found = get_at_path(match, query_string) + if found then + ---@cast found Range6 + table.insert(ranges, found) + end + end + end) + + return ranges +end + +---@param bufnr integer +---@param capture_string string +---@param query_group string +---@param filter_predicate fun(current_range: Range6): boolean +---@param scoring_function fun(current_range: Range6): number +---@return Range6? +function M.find_best_range(bufnr, capture_string, query_group, filter_predicate, scoring_function) + local parser = ts.get_parser(bufnr) + if not parser then + return {} + end + parser:parse(true) + + local first_tree = parser:trees()[1] + local root = first_tree:root() + local lang = parser:lang() + + if string.sub(capture_string, 1, 1) == '@' then + --remove leading "@" + capture_string = string.sub(capture_string, 2) + end + + local best ---@type Range6? + local best_score ---@type number + + local matches = get_query_matches(bufnr, query_group, root, lang) + for _, maybe_match in pairs(matches) do + local range = get_at_path(maybe_match, capture_string) + ---@cast range Range6 + + if range and filter_predicate(range) then + local current_score = scoring_function(range) + if not best then + best = range + best_score = current_score + end + if current_score > best_score then + best = range + best_score = current_score + end + end + end + return best +end + +---@param range Range4 +---@param row integer +---@param col integer +---@return boolean +local function is_in_range(range, row, col) + local start_row, start_col, end_row, end_col = unpack(range) ---@type integer, integer, integer, integer + end_col = end_col - 1 + + local is_in_rows = start_row <= row and end_row >= row + local is_after_start_col_if_needed = true + if start_row == row then + is_after_start_col_if_needed = col >= start_col + end + local is_before_end_col_if_needed = true + if end_row == row then + is_before_end_col_if_needed = col <= end_col + end + return is_in_rows and is_after_start_col_if_needed and is_before_end_col_if_needed +end + +---@param range1 Range4 +---@param range2 Range4 +---@return boolean +local function contains(range1, range2) + return is_in_range(range1, range2[1], range2[2]) and is_in_range(range1, range2[3], range2[4]) +end + +---@param range Range6 +---@return Range4 +function M.torange4(range) + return { range[1], range[2], range[4], range[5] } +end + +--- Get the best `TSTextObjects.Range` at a given point +--- If the point is inside a `TSTextObjects.Range`, the smallest range is returned +--- If the point is not inside a `TSTextObjects.Range`, the closest one is returned +--- (if `opts.lookahead` or `opts.lookbehind` is true) +---@param ranges Range6[] list of ranges +---@param row number 0-indexed +---@param col number 0-indexed +---@param opts {lookahead: boolean?, lookbehind: boolean?} lookahead and lookbehind options +---@return Range6? +local function best_range_at_point(ranges, row, col, opts) + local range_length ---@type integer + local smallest_range ---@type Range6 + local earliest_start ---@type integer + + local lookahead_match_length ---@type integer + local lookahead_largest_range ---@type Range6 + local lookahead_earliest_start ---@type integer + local lookbehind_match_length ---@type integer + local lookbehind_largest_range ---@type Range6 + local lookbehind_earliest_start ---@type integer + + for _, range in pairs(ranges) do + if range and is_in_range(M.torange4(range), row, col) then + local length = range[6] - range[3] + if not range_length or length < range_length then + smallest_range = range + range_length = length + end + -- for nodes with same length take the one with earliest start + if range_length and length == smallest_range[6] - smallest_range[3] then + local start_byte = range[3] + if not earliest_start or start_byte < earliest_start then + smallest_range = range + range_length = length + earliest_start = start_byte + end + end + elseif opts.lookahead then + local start_line, start_col, start_byte = range[1], range[2], range[3] + if start_line > row or start_line == row and start_col > col then + local length = range[6] - range[3] + if + not lookahead_earliest_start + or lookahead_earliest_start > start_byte + or (lookahead_earliest_start == start_byte and lookahead_match_length < length) + then + lookahead_match_length = length + lookahead_largest_range = range + lookahead_earliest_start = start_byte + end + end + elseif opts.lookbehind then + local start_line, start_col, start_byte = range[1], range[2], range[3] + if start_line < row or start_line == row and start_col < col then + local length = range[6] - range[3] + if + not lookbehind_earliest_start + or lookbehind_earliest_start < start_byte + or (lookbehind_earliest_start == start_byte and lookbehind_match_length > length) + then + lookbehind_match_length = length + lookbehind_largest_range = range + lookbehind_earliest_start = start_byte + end + end + end + end + + if smallest_range then + return smallest_range + elseif lookahead_largest_range then + return lookahead_largest_range + elseif lookbehind_largest_range then + return lookbehind_largest_range + end +end + +--- Get the best range at a given point +--- Similar to `best_range_at_point` but it will search within the `@*.outer` capture if possible. +--- For example, `@function.inner` will select the inner part of what `@function.outer` would select. +--- Without this logic, `@function.inner` can select the larger context (e.g. the main function) +--- when it's just before the start of the inner range. +--- Or it will look ahead and choose the next inner range instead of selecting the current function +--- when it's just after the end of the inner range (e.g. the "end" keyword of the function) +---@param query_string string +---@param query_group string +---@param bufnr? integer +---@param pos? {[1]: integer, [2]: integer} +---@param opts? {lookahead: boolean?, lookbehind: boolean?} lookahead and lookbehind options +---@return Range6? +function M.textobject_at_point(query_string, query_group, bufnr, pos, opts) + opts = opts or {} + bufnr = bufnr or vim.api.nvim_get_current_buf() + pos = pos or vim.api.nvim_win_get_cursor(0) + + local row, col = unpack(pos) --[[@as integer, integer]] + row = row - 1 + + if not string.match(query_string, '^@.*') then + error('Captures must start with "@"') + end + + local ranges = get_capture_ranges_recursively(bufnr, query_string, query_group) + if vim.endswith(query_string, 'outer') then + local range = best_range_at_point(ranges, row, col, opts) + return range + else + -- query string is @*.inner or @* + -- First search the @*.outer instead, and then search the @*.inner within the range of the @*.outer + local query_string_outer = string.gsub(query_string, '%..*', '.outer') + if query_string_outer == query_string then + query_string_outer = query_string .. '.outer' + end + + local ranges_outer = get_capture_ranges_recursively(bufnr, query_string_outer, query_group) + if #ranges_outer == 0 then + -- Outer query doesn't exist or doesn't match anything + -- Return the best range from the entire buffer, just like the @*.outer case + local range = best_range_at_point(ranges, row, col, opts) + return range + end + + -- Note that outer ranges don't perform lookahead + local range_outer = best_range_at_point(ranges_outer, row, col, {}) + if range_outer == nil then + -- No @*.outer found + -- Return the best range from the entire buffer, just like the @*.outer case + local range = best_range_at_point(ranges, row, col, opts) + return range + end + + local ranges_within_outer = {} + for _, range in ipairs(ranges) do + if contains(M.torange4(range_outer), M.torange4(range)) then + table.insert(ranges_within_outer, range) + end + end + if #ranges_within_outer == 0 then + -- No @*.inner found within the range of the @*.outer + -- Return the best range from the entire buffer, just like the @*.outer case + local range = best_range_at_point(ranges, row, col, opts) + return range + else + -- Find the best range from the cursor position + local range = best_range_at_point(ranges_within_outer, row, col, opts) + if range ~= nil then + return range + else + -- If failed, + -- find the best range within the range of the @*.outer + -- starting from the outer range's start position (not the cursor position) + -- with lookahead enabled + range = best_range_at_point( + ranges_within_outer, + range_outer[1], + range_outer[2], + { lookahead = true } + ) + return range + end + end + end +end + +---@param lang? string +---@param query_group? string +---@return string[] +M.available_textobjects = memoize(function(lang, query_group) + if not lang then + return {} + end + + query_group = query_group or 'textobjects' + local parsed_queries = + ts.query.get(lang_to_parser[lang] and lang_to_parser[lang] or lang, query_group) + if not parsed_queries then + return {} + end + + return parsed_queries.captures or {} +end, function(lang, query_group) + return string.format('%s-%s', lang, query_group) +end) + +---@param bufnr integer +---@param query_group? string +---@param queries? string[] +--- @return boolean +function M.check_support(bufnr, query_group, queries) + query_group = query_group or 'textobjects' + + local filetype = vim.bo[bufnr].filetype + local buf_lang = ts.language.get_lang(filetype) or filetype + if not buf_lang then + return false + end + local parser = ts.get_parser(bufnr, buf_lang) + if not parser then + return false + end + + local available_textobjects = M.available_textobjects(buf_lang, query_group) + if not available_textobjects then + return false + end + + if queries then + if vim.tbl_isempty(queries) then + return false + end + + for _, query in ipairs(queries) do + if not vim.list_contains(available_textobjects, query:sub(2)) then + return false + end + end + return true + end + + return true +end + +return M diff --git a/lua/nvim-treesitter-textobjects/swap.lua b/lua/nvim-treesitter-textobjects/swap.lua new file mode 100644 index 00000000..d514ac8b --- /dev/null +++ b/lua/nvim-treesitter-textobjects/swap.lua @@ -0,0 +1,224 @@ +local api = vim.api + +local shared = require('nvim-treesitter-textobjects.shared') + +---@class TSTextObjects.LspLocation +---@field line integer +---@field character integer + +---@param range Range4 +---@return lsp.Range +local function to_lsp_range(range) + ---@type integer, integer, integer, integer + local start_row, start_col, end_row, end_col = unpack(range) + return { + start = { + line = start_row, + character = start_col, + }, + ['end'] = { + line = end_row, + character = end_col, + }, + } +end + +---@param range1 Range4 +---@param range2 Range4 +---@param bufnr integer +---@param cursor_to_second any +local function swap_nodes(range1, range2, bufnr, cursor_to_second) + if not range1 or not range2 then + return + end + + local text1 = api.nvim_buf_get_text(bufnr, range1[1], range1[2], range1[3], range1[4], {}) + local text2 = api.nvim_buf_get_text(bufnr, range2[1], range2[2], range2[3], range2[4], {}) + + local lsp_range1 = to_lsp_range(range1) + local lsp_range2 = to_lsp_range(range2) + + local edit1 = { range = lsp_range1, newText = table.concat(text2, '\n') } + local edit2 = { range = lsp_range2, newText = table.concat(text1, '\n') } + vim.lsp.util.apply_text_edits({ edit1, edit2 }, bufnr, 'utf-8') + + if cursor_to_second then + vim.cmd("normal! m'") -- set jump + + local char_delta = 0 + local line_delta = 0 + if + lsp_range1['end'].line < lsp_range2.start.line + or ( + lsp_range1['end'].line == lsp_range2.start.line + and lsp_range1['end'].character <= lsp_range2.start.character + ) + then + line_delta = #text2 - #text1 + end + + if + lsp_range1['end'].line == lsp_range2.start.line + and lsp_range1['end'].character <= lsp_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] - lsp_range1['end'].character + + -- add range1.start.character if last line of range1 (now text2) does not start at 0 + if lsp_range1.start.line == lsp_range2.start.line + line_delta then + char_delta = char_delta + lsp_range1.start.character + end + else + char_delta = #text2[#text2] - #text1[#text1] + end + end + + api.nvim_win_set_cursor( + api.nvim_get_current_win(), + { lsp_range2.start.line + 1 + line_delta, lsp_range2.start.character + char_delta } + ) + end +end + +---@param range1 Range6 +---@param range2 Range6 +local function range_eq(range1, range2) + local srow1, scol1, _, erow1, ecol1, _ = unpack(range1) ---@type integer, integer, integer, integer, integer, integer + local srow2, scol2, _, erow2, ecol2, _ = unpack(range2) ---@type integer, integer, integer, integer, integer, integer + return srow1 == srow2 and scol1 == scol2 and erow1 == erow2 and ecol1 == ecol2 +end + +--- +---@param range Range6 +---@param query_string string +---@param query_group string +---@param bufnr integer +---@return Range6? +local next_textobject = function(range, query_string, query_group, bufnr) + local node_end = range[6] + local search_start = node_end + + ---@param current_range Range6 + ---@return boolean + local function filter_function(current_range) + if range_eq(current_range, range) then + return false + end + local start = current_range[3] + local end_ = current_range[6] + return start >= search_start and end_ >= node_end + end + + ---@param current_range Range6 + ---@return integer + local function scoring_function(current_range) + local start = current_range[3] + return -start + end + + local next_range = + shared.find_best_range(bufnr, query_string, query_group, filter_function, scoring_function) + + return next_range +end + +---@param range Range6 +---@param query_string string +---@param query_group string +---@param bufnr integer +---@return Range6? +local previous_textobject = function(range, query_string, query_group, bufnr) + local node_start = range[3] + local search_end = node_start + + ---@param current_range Range6 + ---@return boolean + local function filter_function(current_range) + local start = current_range[3] + local end_ = current_range[6] + return end_ <= search_end and start < node_start + end + + ---@param current_range Range6 + ---@return integer + local function scoring_function(current_range) + local node_end = current_range[6] + return node_end + end + + local previous_range = + shared.find_best_range(bufnr, query_string, query_group, filter_function, scoring_function) + + return previous_range +end + +local M = {} + +---@param query_strings string|string[] +---@param query_group? string +---@param direction integer +local function swap_textobject(query_strings, query_group, direction) + if type(query_strings) == 'string' then + query_strings = { query_strings } + end + query_group = query_group or 'textobjects' + local bufnr = vim.api.nvim_get_current_buf() + + local textobject_range, query_string ---@type Range6?, string? + for _, query_string_iter in ipairs(query_strings) do + textobject_range = shared.textobject_at_point(query_string_iter, query_group, bufnr) + if textobject_range then + query_string = query_string_iter + break + end + end + if not query_string or not textobject_range then + return + end + + local step = direction > 0 and 1 or -1 + for _ = 1, math.abs(direction), step do + local adjacent = direction > 0 + and next_textobject(textobject_range, query_string, query_group, bufnr) + or previous_textobject(textobject_range, query_string, query_group, bufnr) + if adjacent then + swap_nodes( + shared.torange4(textobject_range), + shared.torange4(adjacent), + bufnr, + 'yes, set cursor!' + ) + end + end +end + +---@param fn function +local function make_dot_repeatable(fn) + _G._nvim_treesitter_textobject_last_function = fn + vim.o.opfunc = 'v:lua._nvim_treesitter_textobject_last_function' + api.nvim_feedkeys('g@l', 'n', false) +end + +---@param query_strings string lua pattern describing the query string +---@param query_group? string +function M.swap_next(query_strings, query_group) + return make_dot_repeatable(function() + swap_textobject(query_strings, query_group, 1) + end) +end + +---@param query_strings string lua pattern describing the query string +---@param query_group? string +function M.swap_previous(query_strings, query_group) + return make_dot_repeatable(function() + swap_textobject(query_strings, query_group, -1) + end) +end + +return M diff --git a/lua/nvim-treesitter/textobjects/attach.lua b/lua/nvim-treesitter/textobjects/attach.lua deleted file mode 100644 index 70a31b6a..00000000 --- a/lua/nvim-treesitter/textobjects/attach.lua +++ /dev/null @@ -1,83 +0,0 @@ -local configs = require "nvim-treesitter.configs" -local M = {} - -local function make_dot_repeatable(fn) - return function() - _G._nvim_treesitter_textobject_last_function = fn - vim.o.opfunc = "v:lua._nvim_treesitter_textobject_last_function" - vim.api.nvim_feedkeys("g@l", "n", false) - end -end - -M.keymaps_per_submodule = {} - -function M.make_attach(functions, submodule, keymap_modes, opts) - if type(keymap_modes) == "string" then - keymap_modes = { keymap_modes } - elseif type(keymap_modes) ~= "table" then - keymap_modes = { "n" } - end - opts = opts or {} - - M.keymaps_per_submodule[submodule] = M.keymaps_per_submodule[submodule] or {} - local keymaps_per_buf = M.keymaps_per_submodule[submodule] - - return function(bufnr, lang) - -- lang = lang or parsers.get_buf_lang(bufnr) - local config = configs.get_module("textobjects." .. submodule) - - for _, function_call in pairs(functions) do - local function_description = function_call:gsub("_", " "):gsub("^%l", string.upper) - for mapping, query_metadata in pairs(config[function_call] or {}) do - local mapping_description, query, query_group - - if type(query_metadata) == "table" then - query = query_metadata.query - query_group = query_metadata.query_group or "textobjects" - mapping_description = query_metadata.desc - else - query = query_metadata - query_group = "textobjects" - mapping_description = function_description .. " " .. query_metadata - end - - local fn = function() - require("nvim-treesitter.textobjects." .. submodule)[function_call](query, query_group) - end - if opts.dot_repeatable then - fn = make_dot_repeatable(fn) - end - for _, mode in pairs(keymap_modes) do - local status, _ = pcall( - vim.keymap.set, - mode, - mapping, - fn, - { buffer = bufnr, silent = true, remap = false, desc = mapping_description } - ) - if status then - keymaps_per_buf[bufnr] = keymaps_per_buf[bufnr] or {} - table.insert(keymaps_per_buf[bufnr], { mode = mode, lhs = mapping }) - end - end - end - end - end -end - -function M.make_detach(submodule) - return function(bufnr) - M.keymaps_per_submodule[submodule] = M.keymaps_per_submodule[submodule] or {} - local keymaps_per_buf = M.keymaps_per_submodule[submodule] - - bufnr = bufnr or vim.api.nvim_get_current_buf() - - for _, keymap in ipairs(keymaps_per_buf[bufnr] or {}) do - -- Even if it fails make it silent - pcall(vim.keymap.del, { keymap.mode }, keymap.lhs, { buffer = bufnr }) - end - keymaps_per_buf[bufnr] = nil - end -end - -return M diff --git a/lua/nvim-treesitter/textobjects/lsp_interop.lua b/lua/nvim-treesitter/textobjects/lsp_interop.lua deleted file mode 100644 index d89d2ead..00000000 --- a/lua/nvim-treesitter/textobjects/lsp_interop.lua +++ /dev/null @@ -1,136 +0,0 @@ -local attach = require "nvim-treesitter.textobjects.attach" -local shared = require "nvim-treesitter.textobjects.shared" -local configs = require "nvim-treesitter.configs" - -local M = {} - -local floating_win - --- NOTE: This can be replaced with `vim.islist` once Neovim 0.9 support is dropped -local islist = vim.fn.has "nvim-0.10" == 1 and vim.islist or vim.tbl_islist - --- peeking is not interruptive so it is okay to use in visual mode. --- in fact, visual mode peeking is very helpful because you may not want --- to jump to the definition. -local nx_mode_functions = { - "peek_definition_code", -} - -local function is_new_signature_handler() - if debug.getinfo(vim.lsp.handlers.signature_help).nparams == 4 then - return true - else - return false - end -end - -function M.preview_location(location, context) - -- location may be LocationLink or Location (more useful for the former) - local uri = location.targetUri or location.uri - if uri == nil then - return - end - local bufnr = vim.uri_to_bufnr(uri) - if not vim.api.nvim_buf_is_loaded(bufnr) then - vim.fn.bufload(bufnr) - end - - local range = location.targetRange or location.range - -- don't include a exclusive 0 character line - if range["end"].character == 0 then - range["end"].line = range["end"].line - 1 - end - if type(context) == "table" then - range.start.line = math.min(range.start.line, context[1]) - range["end"].line = math.max(range["end"].line, context[3]) - elseif type(context) == "number" then - range["end"].line = math.max(range["end"].line, range.start.line + context) - end - - local config = configs.get_module "textobjects.lsp_interop" - local opts = config.floating_preview_opts or {} - - if config.border ~= "none" then - opts.border = config.border - end - local contents = vim.api.nvim_buf_get_lines(bufnr, range.start.line, range["end"].line + 1, false) - local filetype = vim.api.nvim_buf_get_option(bufnr, "filetype") - local preview_buf, preview_win = vim.lsp.util.open_floating_preview(contents, filetype, opts) - vim.api.nvim_buf_set_option(preview_buf, "filetype", filetype) - return preview_buf, preview_win -end - -function M.make_preview_location_callback(query_string, query_group, context) - query_group = query_group or "textobjects" - context = context or 0 - local callback = function(err, method, result) - if err then - error(tostring(err)) - end - if result == nil or vim.tbl_isempty(result) then - print("No location found: " .. (method or "unknown error")) - return - end - - if islist(result) then - result = result[1] - end - local uri = result.uri or result.targetUri - local range = result.range or result.targetRange - if not uri or not range then - return - end - - local buf = vim.uri_to_bufnr(uri) - vim.fn.bufload(buf) - - local _, textobject_at_definition = - shared.textobject_at_point(query_string, query_group, { range.start.line + 1, range.start.character }, buf) - - if textobject_at_definition then - context = textobject_at_definition - end - - _, floating_win = M.preview_location(result, context) - end - - local signature_handler = callback - - if is_new_signature_handler() then - signature_handler = function(err, result, handler_context) - callback(err, handler_context.method, result) - end - end - - return vim.schedule_wrap(signature_handler) -end - -function M.peek_definition_code(query_string, query_group, lsp_request, context) - query_group = query_group or "textobjects" - lsp_request = lsp_request or "textDocument/definition" - if vim.tbl_contains(vim.api.nvim_list_wins(), floating_win) then - vim.api.nvim_set_current_win(floating_win) - else - local params = vim.lsp.util.make_position_params() - return vim.lsp.buf_request( - 0, - lsp_request, - params, - M.make_preview_location_callback(query_string, query_group, context) - ) - end -end - -M.attach = attach.make_attach(nx_mode_functions, "lsp_interop", { "n", "x" }) -M.detach = attach.make_detach "lsp_interop" -M.commands = { - TSTextobjectPeekDefinitionCode = { - run = M.peek_definition_code, - args = { - "-nargs=+", - "-complete=custom,nvim_treesitter_textobjects#available_textobjects", - }, - }, -} - -return M diff --git a/lua/nvim-treesitter/textobjects/move.lua b/lua/nvim-treesitter/textobjects/move.lua deleted file mode 100644 index 292119d9..00000000 --- a/lua/nvim-treesitter/textobjects/move.lua +++ /dev/null @@ -1,196 +0,0 @@ -local ts_utils = require "nvim-treesitter.ts_utils" -local attach = require "nvim-treesitter.textobjects.attach" -local shared = require "nvim-treesitter.textobjects.shared" -local repeatable_move = require "nvim-treesitter.textobjects.repeatable_move" -local queries = require "nvim-treesitter.query" -local configs = require "nvim-treesitter.configs" -local parsers = require "nvim-treesitter.parsers" - -local M = {} - -local function move(opts) - -- opts includes query_strings_regex, query_group, forward, start, winid - -- start: bool or nil. If true, choose the start of the node, and false is for the end. - -- If nil, it considers both and chooses the closer side. - local query_strings_regex = shared.make_query_strings_table(opts.query_strings_regex) - local query_group = opts.query_group or "textobjects" - local forward = opts.forward - local starts - if opts.start == nil then - starts = { true, false } - else - if opts.start then - starts = { true } - else - starts = { false } - end - end - local winid = opts.winid or vim.api.nvim_get_current_win() - - local bufnr = vim.api.nvim_win_get_buf(winid) - local query_strings = - shared.get_query_strings_from_regex(query_strings_regex, query_group, parsers.get_buf_lang(bufnr)) - - local config = configs.get_module "textobjects.move" - - -- score is a byte position. - local function scoring_function(start_, match) - local score, _ - if start_ then - _, _, score = match.node:start() - else - _, _, score = match.node:end_() - end - if forward then - return -score - else - return score - end - end - - local function filter_function(start_, match) - local range = { match.node:range() } - local row, col = unpack(vim.api.nvim_win_get_cursor(winid)) - row = row - 1 -- nvim_win_get_cursor is (1,0)-indexed - - if not start_ then - if range[4] == 0 then - range[1] = range[3] - 1 - range[2] = range[4] - else - range[1] = range[3] - range[2] = range[4] - 1 - end - end - if forward then - return range[1] > row or (range[1] == row and range[2] > col) - else - return range[1] < row or (range[1] == row and range[2] < col) - end - end - - for _ = 1, vim.v.count1 do - local best_match - local best_score - local best_start - for _, query_string in ipairs(query_strings) do - for _, start_ in ipairs(starts) do - local current_match = queries.find_best_match(bufnr, query_string, query_group, function(match) - return filter_function(start_, match) - end, function(match) - return scoring_function(start_, match) - end) - - if current_match then - local score = scoring_function(start_, current_match) - if not best_match then - best_match = current_match - best_score = score - best_start = start_ - end - if score > best_score then - best_match = current_match - best_score = score - best_start = start_ - end - end - end - end - ts_utils.goto_node(best_match and best_match.node, not best_start, not config.set_jumps) - end -end - -local move_repeatable = repeatable_move.make_repeatable_move(move) - -M.goto_next_start = function(query_strings_regex, query_group) - move_repeatable { - forward = true, - start = true, - query_strings_regex = query_strings_regex, - query_group = query_group, - } -end -M.goto_next_end = function(query_strings_regex, query_group) - move_repeatable { - forward = true, - start = false, - query_strings_regex = query_strings_regex, - query_group = query_group, - } -end -M.goto_previous_start = function(query_strings_regex, query_group) - move_repeatable { - forward = false, - start = true, - query_strings_regex = query_strings_regex, - query_group = query_group, - } -end -M.goto_previous_end = function(query_strings_regex, query_group) - move_repeatable { - forward = false, - start = false, - query_strings_regex = query_strings_regex, - query_group = query_group, - } -end - -M.goto_next = function(query_strings_regex, query_group) - move_repeatable { - forward = true, - query_strings_regex = query_strings_regex, - query_group = query_group, - } -end -M.goto_previous = function(query_strings_regex, query_group) - move_repeatable { - forward = false, - query_strings_regex = query_strings_regex, - query_group = query_group, - } -end - -local nxo_mode_functions = { - "goto_next_start", - "goto_next_end", - "goto_previous_start", - "goto_previous_end", - "goto_next", - "goto_previous", -} - -M.attach = attach.make_attach(nxo_mode_functions, "move", { "n", "x", "o" }) -M.detach = attach.make_detach "move" - -M.commands = { - TSTextobjectGotoNextStart = { - run = M.goto_next_start, - args = { - "-nargs=1", - "-complete=custom,nvim_treesitter_textobjects#available_textobjects", - }, - }, - TSTextobjectGotoNextEnd = { - run = M.goto_next_end, - args = { - "-nargs=1", - "-complete=custom,nvim_treesitter_textobjects#available_textobjects", - }, - }, - TSTextobjectGotoPreviousStart = { - run = M.goto_previous_start, - args = { - "-nargs=1", - "-complete=custom,nvim_treesitter_textobjects#available_textobjects", - }, - }, - TSTextobjectGotoPreviousEnd = { - run = M.goto_previous_end, - args = { - "-nargs=1", - "-complete=custom,nvim_treesitter_textobjects#available_textobjects", - }, - }, -} - -return M diff --git a/lua/nvim-treesitter/textobjects/repeatable_move.lua b/lua/nvim-treesitter/textobjects/repeatable_move.lua deleted file mode 100644 index 700a7d5f..00000000 --- a/lua/nvim-treesitter/textobjects/repeatable_move.lua +++ /dev/null @@ -1,340 +0,0 @@ --- If you are a plugin developer (or just want to make other movement plugins repeatable), --- you can register your own independent move functions --- even if they are not related to treesitter-textobjects. --- Use one of the followings: --- M.make_repeatable_move(move_fn) --- M.make_repeatable_move_pair(forward_move_fn, backward_move_fn) --- M.set_last_move(move_fn, opts, ...) --- --- Then you can use four functions to repeat the last movement: --- M.repeat_last_move --- M.repeat_last_move_opposite --- M.repeat_last_move_next --- M.repeat_last_move_previous - -local M = {} - -M.last_move = nil --- { func = move, opts = { ... }, additional_args = {} } --- { func = "f", opts = { ... }, additional_args = {} } --- register any other function, but make sure the the first args is an opts table with a `forward` boolean. --- prefer to set using M.set_last_move - -M.clear_last_move = function() - M.last_move = nil -end - --- move_fn's first argument must be a table of options, and it should include a `forward` boolean --- indicating whether to move forward (true) or backward (false) -M.set_last_move = function(move_fn, opts, ...) - if type(move_fn) ~= "function" then - vim.notify( - "nvim-treesitter-textobjects: move_fn has to be a function but got " .. vim.inspect(move_fn), - vim.log.levels.ERROR - ) - return false - end - - if type(opts) ~= "table" then - vim.notify( - "nvim-treesitter-textobjects: opts has to be a table but got " .. vim.inspect(opts), - vim.log.levels.ERROR - ) - return false - elseif opts.forward == nil then - vim.notify( - "nvim-treesitter-textobjects: opts has to include a `forward` boolean but got " .. vim.inspect(opts), - vim.log.levels.ERROR - ) - return false - end - - M.last_move = { func = move_fn, opts = vim.deepcopy(opts), additional_args = { ... } } - return true -end - --- Pass a function that takes a table of options (should include `forward` boolean) --- and it returns the same function that is magically repeatable -M.make_repeatable_move = function(move_fn) - return function(opts, ...) - M.set_last_move(move_fn, opts, ...) - move_fn(opts, ...) - end -end - --- Alternative: --- Get a movement function pair (forward, backward) and turn them into two repeatable movement functions --- They don't need to have the first argument as a table of options -M.make_repeatable_move_pair = function(forward_move_fn, backward_move_fn) - local general_repeatable_move_fn = function(opts, ...) - if opts.forward then - forward_move_fn(...) - else - backward_move_fn(...) - end - end - - local repeatable_forward_move_fn = function(...) - M.set_last_move(general_repeatable_move_fn, { forward = true }, ...) - forward_move_fn(...) - end - - local repeatable_backward_move_fn = function(...) - M.set_last_move(general_repeatable_move_fn, { forward = false }, ...) - backward_move_fn(...) - end - - return repeatable_forward_move_fn, repeatable_backward_move_fn -end - -M.repeat_last_move = function(opts_extend) - if M.last_move then - local opts - if opts_extend ~= nil then - if type(opts_extend) ~= "table" then - vim.notify( - "nvim-treesitter-textobjects: opts_extend has to be a table but got " .. vim.inspect(opts_extend), - vim.log.levels.ERROR - ) - return false - end - - opts = vim.tbl_deep_extend("force", {}, M.last_move.opts, opts_extend) - else - opts = M.last_move.opts - end - - if M.last_move.func == "f" or M.last_move.func == "t" then - if opts.forward then - vim.cmd([[normal! ]] .. vim.v.count1 .. ";") - else - vim.cmd([[normal! ]] .. vim.v.count1 .. ",") - end - elseif M.last_move.func == "F" or M.last_move.func == "T" then - if opts.forward then - vim.cmd([[normal! ]] .. vim.v.count1 .. ",") - else - vim.cmd([[normal! ]] .. vim.v.count1 .. ";") - end - else - M.last_move.func(opts, unpack(M.last_move.additional_args)) - end - return true - end - return false -end - -M.repeat_last_move_opposite = function() - return M.last_move and M.repeat_last_move { forward = not M.last_move.opts.forward } -end - -M.repeat_last_move_next = function() - return M.repeat_last_move { forward = true } -end - -M.repeat_last_move_previous = function() - return M.repeat_last_move { forward = false } -end - --- NOTE: map builtin_f_expr, builtin_F_expr, builtin_t_expr, builtin_T_expr with { expr = true }. --- --- We are not using M.make_repeatable_move or M.set_last_move and instead registering at M.last_move manually --- because move_fn is not a function (but string f, F, t, T). --- We don't want to execute a move function, but instead return an expression (f, F, t, T). -M.builtin_f_expr = function() - M.last_move = { - func = "f", - opts = { forward = true }, - additional_args = {}, - } - return "f" -end - -M.builtin_F_expr = function() - M.last_move = { - func = "F", - opts = { forward = false }, - additional_args = {}, - } - return "F" -end - -M.builtin_t_expr = function() - M.last_move = { - func = "t", - opts = { forward = true }, - additional_args = {}, - } - return "t" -end - -M.builtin_T_expr = function() - M.last_move = { - func = "T", - opts = { forward = false }, - additional_args = {}, - } - return "T" -end - --- implements naive f, F, t, T with repeat support ----@deprecated -local function builtin_find(opts) - -- opts include forward, inclusive, char, repeating, winid - -- forward = true -> f, t - -- inclusive = false -> t, T - -- if repeating with till (t or T, inclusive = false) then search from the next character - -- returns nil if cancelled or char - local forward = opts.forward - local inclusive = opts.inclusive - local char = opts.char or vim.fn.nr2char(vim.fn.getchar()) - local repeating = opts.repeating or false - local winid = opts.winid or vim.api.nvim_get_current_win() - - if char == vim.fn.nr2char(27) then - -- escape - return nil - end - - local line = vim.api.nvim_get_current_line() - local cursor = vim.api.nvim_win_get_cursor(winid) - - -- count works like this with builtin vim motions. - -- weird, but we're matching the behaviour - local count - if not inclusive and repeating then - count = math.max(vim.v.count1 - 1, 1) - else - count = vim.v.count1 - end - - -- find the count-th occurrence of the char in the line - local found - for _ = 1, count do - if forward then - if not inclusive and repeating then - cursor[2] = cursor[2] + 1 - end - found = line:find(char, cursor[2] + 2, true) - else - -- reverse find from the cursor position - if not inclusive and repeating then - cursor[2] = cursor[2] - 1 - end - - found = line:reverse():find(char, #line - cursor[2] + 1, true) - if found then - found = #line - found + 1 - end - end - - if not found then - return char - end - - if forward then - if not inclusive then - found = found - 1 - end - else - if not inclusive then - found = found + 1 - end - end - - cursor[2] = found - 1 - repeating = true -- after the first iteration, search from the next character if not inclusive. - 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 - - -- move to the found position - vim.api.nvim_win_set_cursor(winid, { cursor[1], cursor[2] }) - return char -end - --- We are not using M.make_repeatable_move and instead registering at M.last_move manually --- because we don't want to behave the same way as the first movement. --- For example, we want to repeat the search character given to f, F, t, T. --- Also, we want to be able to to find the next occurence when using t, T with repeat, excluding the current position. ----@deprecated -M.builtin_f = function() - vim.notify_once("nvim-treesitter-textobjects: map `builtin_f_expr` with `{expr=true}` instead.", vim.log.levels.WARN) - local opts = { forward = true, inclusive = true } - local char = builtin_find(opts) - if char ~= nil then - opts.char = char - opts.repeating = true - M.set_last_move(builtin_find, opts) - end -end - ----@deprecated -M.builtin_F = function() - vim.notify_once("nvim-treesitter-textobjects: map `builtin_F_expr` with `{expr=true}` instead.", vim.log.levels.WARN) - local opts = { forward = false, inclusive = true } - local char = builtin_find(opts) - if char ~= nil then - opts.char = char - opts.repeating = true - M.set_last_move(builtin_find, opts) - end -end - ----@deprecated -M.builtin_t = function() - vim.notify_once("nvim-treesitter-textobjects: map `builtin_t_expr` with `{expr=true}` instead.", vim.log.levels.WARN) - local opts = { forward = true, inclusive = false } - local char = builtin_find(opts) - if char ~= nil then - opts.char = char - opts.repeating = true - M.set_last_move(builtin_find, opts) - end -end - ----@deprecated -M.builtin_T = function() - vim.notify_once("nvim-treesitter-textobjects: map `builtin_T_expr` with `{expr=true}` instead.", vim.log.levels.WARN) - local opts = { forward = false, inclusive = false } - local char = builtin_find(opts) - if char ~= nil then - opts.char = char - opts.repeating = true - M.set_last_move(builtin_find, opts) - end -end - -M.commands = { - TSTextobjectRepeatLastMove = { - run = M.repeat_last_move, - }, - TSTextobjectRepeatLastMoveOpposite = { - run = M.repeat_last_move_opposite, - }, - TSTextobjectRepeatLastMoveNext = { - run = M.repeat_last_move_next, - }, - TSTextobjectRepeatLastMovePrevious = { - run = M.repeat_last_move_previous, - }, - TSTextobjectBuiltinf = { - run = M.builtin_f, - }, - TSTextobjectBuiltinF = { - run = M.builtin_F, - }, - TSTextobjectBuiltint = { - run = M.builtin_t, - }, - TSTextobjectBuiltinT = { - run = M.builtin_T, - }, -} - -return M diff --git a/lua/nvim-treesitter/textobjects/select.lua b/lua/nvim-treesitter/textobjects/select.lua deleted file mode 100644 index 2f6dc885..00000000 --- a/lua/nvim-treesitter/textobjects/select.lua +++ /dev/null @@ -1,229 +0,0 @@ -local api = vim.api -local configs = require "nvim-treesitter.configs" -local parsers = require "nvim-treesitter.parsers" - -local shared = require "nvim-treesitter.textobjects.shared" -local ts_utils = require "nvim-treesitter.ts_utils" - -local M = {} - -local function get_char_after_position(bufnr, row, col) - if row == nil then - return nil - end - local ok, char = pcall(vim.api.nvim_buf_get_text, bufnr, row, col, row, col + 1, {}) - if ok then - return char[1] - end -end - -local function is_whitespace_after(bufnr, row, col) - local char = get_char_after_position(bufnr, row, col) - if char == nil then - return false - end - if char == "" then - if row == vim.api.nvim_buf_line_count(bufnr) - 1 then - return false - else - return true - end - end - return string.match(char, "%s") -end - -local function get_line(bufnr, row) - return vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1] -end - -local function next_position(bufnr, row, col, forward) - local max_col = #get_line(bufnr, row) - local max_row = vim.api.nvim_buf_line_count(bufnr) - if forward then - if col == max_col then - if row == max_row then - return nil - end - row = row + 1 - col = 0 - else - col = col + 1 - end - else - if col == 0 then - if row == 0 then - return nil - end - row = row - 1 - col = #get_line(bufnr, row) - else - col = col - 1 - end - end - return row, col -end - -local function include_surrounding_whitespace(bufnr, textobject, selection_mode) - local start_row, start_col, end_row, end_col = unpack(textobject) - local extended = false - while is_whitespace_after(bufnr, end_row, end_col) do - extended = true - end_row, end_col = next_position(bufnr, end_row, end_col, true) - end - if extended then - -- don't extend in both directions - return { start_row, start_col, end_row, end_col } - end - local next_row, next_col = next_position(bufnr, start_row, start_col, false) - while is_whitespace_after(bufnr, next_row, next_col) do - start_row = next_row - start_col = next_col - next_row, next_col = next_position(bufnr, start_row, start_col, false) - end - if selection_mode == "linewise" then - start_row, start_col = next_position(bufnr, start_row, start_col, true) - end - return { start_row, start_col, end_row, end_col } -end - -local val_or_return = function(val, opts) - if type(val) == "function" then - return val(opts) - else - return val - end -end - -function M.select_textobject(query_string, query_group, keymap_mode) - query_group = query_group or "textobjects" - local lookahead = configs.get_module("textobjects.select").lookahead - local lookbehind = configs.get_module("textobjects.select").lookbehind - local surrounding_whitespace = configs.get_module("textobjects.select").include_surrounding_whitespace - local bufnr, textobject = - shared.textobject_at_point(query_string, query_group, nil, nil, { lookahead = lookahead, lookbehind = lookbehind }) - if textobject then - local selection_mode = M.detect_selection_mode(query_string, keymap_mode) - if - val_or_return(surrounding_whitespace, { - query_string = query_string, - selection_mode = selection_mode, - }) - then - textobject = include_surrounding_whitespace(bufnr, textobject, selection_mode) - end - ts_utils.update_selection(bufnr, textobject, selection_mode) - end -end - -function M.detect_selection_mode(query_string, keymap_mode) - -- Update selection mode with different methods based on keymapping mode - local keymap_to_method = { - o = "operator-pending", - s = "visual", - v = "visual", - x = "visual", - } - local method = keymap_to_method[keymap_mode] - - local config = configs.get_module "textobjects.select" - local selection_modes = val_or_return(config.selection_modes, { query_string = query_string, method = method }) - local selection_mode - if type(selection_modes) == "table" then - selection_mode = selection_modes[query_string] or "v" - else - selection_mode = selection_modes or "v" - end - - local ret_value = selection_mode - local mode = vim.fn.mode(1) - local is_normal_or_charwise_v = mode == "n" or mode == "v" - - if not is_normal_or_charwise_v then - -- According to "mode()" mapping, if we are in operator pending mode or visual mode, - -- then last char is {v,V,}, exept for "no", which is "o", in which case we honor - -- last set `selection_mode` - local visual_mode = mode:sub(#mode) - ret_value = visual_mode == "o" and selection_mode or visual_mode - end - - return ret_value == "n" and "v" or ret_value -end - -M.keymaps_per_buf = {} - -function M.attach(bufnr, lang) - bufnr = bufnr or api.nvim_get_current_buf() - local config = configs.get_module "textobjects.select" - lang = lang or parsers.get_buf_lang(bufnr) - - for mapping, query in pairs(config.keymaps) do - local desc, query_string, query_group - if type(query) == "table" then - desc = query.desc - query_string = query.query - query_group = query.query_group or "textobjects" - else - query_string = query - query_group = "textobjects" - end - if not desc then - desc = "Select textobject " .. query_string - end - - local available_textobjects = shared.available_textobjects(lang, query_group) - local available = false - for _, available_textobject in ipairs(available_textobjects) do - if "@" .. available_textobject == query_string then - available = true - break - end - end - - if not available then - query_string = nil - end - - if query_string then - for _, keymap_mode in ipairs { "o", "x" } do - local status, _ = pcall( - vim.keymap.set, - { keymap_mode }, - mapping, - string.format( - "lua require'nvim-treesitter.textobjects.select'.select_textobject('%s','%s','%s')", - query_string, - query_group, - keymap_mode - ), - { buffer = bufnr, silent = true, remap = false, desc = desc } - ) - if status then - M.keymaps_per_buf[bufnr] = M.keymaps_per_buf[bufnr] or {} - table.insert(M.keymaps_per_buf[bufnr], { mode = keymap_mode, lhs = mapping }) - end - end - end - end -end - -function M.detach(bufnr) - bufnr = bufnr or api.nvim_get_current_buf() - - for _, keymap in ipairs(M.keymaps_per_buf[bufnr] or {}) do - -- Even if it fails make it silent - pcall(vim.keymap.del, { keymap.mode }, keymap.lhs, { buffer = bufnr }) - end - M.keymaps_per_buf[bufnr] = nil -end - -M.commands = { - TSTextobjectSelect = { - run = M.select_textobject, - args = { - "-nargs=1", - "-complete=custom,nvim_treesitter_textobjects#available_textobjects", - }, - }, -} - -return M diff --git a/lua/nvim-treesitter/textobjects/shared.lua b/lua/nvim-treesitter/textobjects/shared.lua deleted file mode 100644 index cd7f97bf..00000000 --- a/lua/nvim-treesitter/textobjects/shared.lua +++ /dev/null @@ -1,377 +0,0 @@ -local api = vim.api - -local parsers = require "nvim-treesitter.parsers" -local queries = require "nvim-treesitter.query" -local ts_utils = require "nvim-treesitter.ts_utils" -local ts = require "nvim-treesitter.compat" - -local M = {} - -if not unpack then - -- luacheck: push ignore 121 - unpack = table.unpack - -- luacheck: pop -end - ---- Similar functions from vim.treesitter, but it accepts node as table type, not necessarily a TSNode -local function _cmp_pos(a_row, a_col, b_row, b_col) - if a_row == b_row then - if a_col > b_col then - return 1 - elseif a_col < b_col then - return -1 - else - return 0 - end - elseif a_row > b_row then - return 1 - end - - return -1 -end - -local cmp_pos = { - lt = function(...) - return _cmp_pos(...) == -1 - end, - le = function(...) - return _cmp_pos(...) ~= 1 - end, - gt = function(...) - return _cmp_pos(...) == 1 - end, - ge = function(...) - return _cmp_pos(...) ~= -1 - end, - eq = function(...) - return _cmp_pos(...) == 0 - end, - ne = function(...) - return _cmp_pos(...) ~= 0 - end, -} - --- This can be replaced to vim.treesitter.node_contains once Neovim 0.9 is released --- In 0.8, it only accepts TSNode type and sometimes it causes issues. -function M.node_contains(node, range) - local srow_1, scol_1, erow_1, ecol_1 = node:range() - local srow_2, scol_2, erow_2, ecol_2 = unpack(range) - - -- start doesn't fit - if cmp_pos.gt(srow_1, scol_1, srow_2, scol_2) then - return false - end - - -- end doesn't fit - if cmp_pos.lt(erow_1, ecol_1, erow_2, ecol_2) then - return false - end - - return true -end - --- Convert single query string to list for backwards compatibility and the Vim commands -function M.make_query_strings_table(query_strings) - return type(query_strings) == "string" and { query_strings } or query_strings -end - --- Get query strings from regex -function M.get_query_strings_from_regex(query_strings_regex, query_group, lang) - query_strings_regex = M.make_query_strings_table(query_strings_regex) - query_group = query_group or "textobjects" - lang = lang or parsers.get_buf_lang(0) - local available_textobjects = M.available_textobjects(lang, query_group) - local query_strings = {} - for _, query_string_regex in ipairs(query_strings_regex) do - for _, available_textobject in ipairs(available_textobjects) do - if string.match("@" .. available_textobject, query_string_regex) then - table.insert(query_strings, "@" .. available_textobject) - end - end - end - - return query_strings -end - -function M.available_textobjects(lang, query_group) - lang = lang or parsers.get_buf_lang() - query_group = query_group or "textobjects" - local parsed_queries = ts.get_query(lang, query_group) - if not parsed_queries then - return {} - end - local found_textobjects = parsed_queries.captures or {} - for _, p in pairs(parsed_queries.info.patterns) do - for _, q in ipairs(p) do - local query, arg1 = unpack(q) - if query == "make-range!" and not vim.tbl_contains(found_textobjects, arg1) then - table.insert(found_textobjects, arg1) - end - end - end - return found_textobjects - --patterns = { - --[2] = { { "make-range!", "function.inner", 2, 3 } }, - --[4] = { { "make-range!", "function.inner", 2, 3 } }, - --[11] = { { "make-range!", "parameter.outer", 2, 12 } }, - --[12] = { { "make-range!", "parameter.outer", 12, 3 } }, - --[13] = { { "make-range!", "parameter.outer", 2, 12 } }, - --[14] = { { "make-range!", "parameter.outer", 12, 3 } } - --} -end - ---- Get the best match at a given point ---- If the point is inside a node, the smallest node is returned ---- If the point is not inside a node, the closest node is returned (if opts.lookahead or opts.lookbehind is true) ----@param matches table list of matches ----@param row number 0-indexed ----@param col number 0-indexed ----@param opts table lookahead and lookbehind options -local function best_match_at_point(matches, row, col, opts) - local match_length - local smallest_range - local earliest_start - - local lookahead_match_length - local lookahead_largest_range - local lookahead_earliest_start - local lookbehind_match_length - local lookbehind_largest_range - local lookbehind_earliest_start - - for _, m in pairs(matches) do - if m.node and vim.treesitter.is_in_node_range(m.node, row, col) then - local length = ts_utils.node_length(m.node) - if not match_length or length < match_length then - smallest_range = m - match_length = length - end - -- for nodes with same length take the one with earliest start - if match_length and length == smallest_range then - local start = m.start - if start then - local _, _, start_byte = m.start.node:start() - if not earliest_start or start_byte < earliest_start then - smallest_range = m - match_length = length - earliest_start = start_byte - end - end - end - elseif opts.lookahead then - local start_line, start_col, start_byte = m.node:start() - if start_line > row or start_line == row and start_col > col then - local length = ts_utils.node_length(m.node) - if - not lookahead_earliest_start - or lookahead_earliest_start > start_byte - or (lookahead_earliest_start == start_byte and lookahead_match_length < length) - then - lookahead_match_length = length - lookahead_largest_range = m - lookahead_earliest_start = start_byte - end - end - elseif opts.lookbehind then - local start_line, start_col, start_byte = m.node:start() - if start_line < row or start_line == row and start_col < col then - local length = ts_utils.node_length(m.node) - if - not lookbehind_earliest_start - or lookbehind_earliest_start < start_byte - or (lookbehind_earliest_start == start_byte and lookbehind_match_length > length) - then - lookbehind_match_length = length - lookbehind_largest_range = m - lookbehind_earliest_start = start_byte - end - end - end - end - - local get_range = function(match) - if match.metadata ~= nil then - return match.metadata.range - end - - return { match.node:range() } - end - - if smallest_range then - if smallest_range.start then - local start_range = get_range(smallest_range.start) - local node_range = get_range(smallest_range) - return { start_range[1], start_range[2], node_range[3], node_range[4] }, smallest_range.node - else - return get_range(smallest_range), smallest_range.node - end - elseif lookahead_largest_range then - return get_range(lookahead_largest_range), lookahead_largest_range.node - elseif lookbehind_largest_range then - return get_range(lookbehind_largest_range), lookbehind_largest_range.node - end -end - ---- Get the best match at a given point ---- Similar to best_match_at_point but it will search within the @*.outer capture if possible. ---- For example, @function.inner will select the inner part of what @function.outer would select. ---- Without this logic, @function.inner can select the larger context (e.g. the main function) ---- when it's just before the start of the inner range. ---- Or it will look ahead and choose the next inner range instead of selecting the current function ---- when it's just after the end of the inner range (e.g. the "end" keyword of the function) -function M.textobject_at_point(query_string, query_group, pos, bufnr, opts) - query_group = query_group or "textobjects" - opts = opts or {} - bufnr = bufnr or vim.api.nvim_get_current_buf() - local lang = parsers.get_buf_lang(bufnr) - if not lang then - return - end - - local row, col = unpack(pos or vim.api.nvim_win_get_cursor(0)) - row = row - 1 - - if not string.match(query_string, "^@.*") then - error 'Captures must start with "@"' - return - end - - local matches = queries.get_capture_matches_recursively(bufnr, query_string, query_group) - if string.match(query_string, "^@.*%.outer$") then - local range, node = best_match_at_point(matches, row, col, opts) - return bufnr, range, node - else - -- query string is @*.inner or @* - -- First search the @*.outer instead, and then search the @*.inner within the range of the @*.outer - local query_string_outer = string.gsub(query_string, "%..*", ".outer") - if query_string_outer == query_string then - query_string_outer = query_string .. ".outer" - end - - local matches_outer = queries.get_capture_matches_recursively(bufnr, query_string_outer, query_group) - if #matches_outer == 0 then - -- Outer query doesn't exist or doesn't match anything - -- Return the best match from the entire buffer, just like the @*.outer case - local range, node = best_match_at_point(matches, row, col, opts) - return bufnr, range, node - end - - -- Note that outer matches don't perform lookahead - local range_outer, node_outer = best_match_at_point(matches_outer, row, col, {}) - if range_outer == nil then - -- No @*.outer found - -- Return the best match from the entire buffer, just like the @*.outer case - local range, node = best_match_at_point(matches, row, col, opts) - return bufnr, range, node - end - - local matches_within_outer = {} - for _, match in ipairs(matches) do - if M.node_contains(node_outer, { match.node:range() }) then - table.insert(matches_within_outer, match) - end - end - if #matches_within_outer == 0 then - -- No @*.inner found within the range of the @*.outer - -- Return the best match from the entire buffer, just like the @*.outer case - local range, node = best_match_at_point(matches, row, col, opts) - return bufnr, range, node - else - -- Find the best match from the cursor position - local range, node = best_match_at_point(matches_within_outer, row, col, opts) - if range ~= nil then - return bufnr, range, node - else - -- If failed, - -- find the best match within the range of the @*.outer - -- starting from the outer range's start position (not the cursor position) - -- with lookahead enabled - range, node = best_match_at_point(matches_within_outer, range_outer[1], range_outer[2], { lookahead = true }) - return bufnr, range, node - end - end - end -end - -function M.get_adjacent(forward, node, query_string, query_group, same_parent, overlapping_range_ok, bufnr) - query_group = query_group or "textobjects" - local fn = forward and M.next_textobject or M.previous_textobject - return fn(node, query_string, query_group, same_parent, overlapping_range_ok, bufnr) -end - -function M.next_textobject(node, query_string, query_group, same_parent, overlapping_range_ok, bufnr) - query_group = query_group or "textobjects" - local node = node or vim.treesitter.get_node_at_cursor() - local bufnr = bufnr or api.nvim_get_current_buf() - if not node then - return - end - - local _, _, node_end = node:end_() - local search_start, _ - if overlapping_range_ok then - _, _, search_start = node:start() - search_start = search_start + 1 - else - _, _, search_start = node:end_() - end - local function filter_function(match) - if match.node == node then - return - end - if not same_parent or node:parent() == match.node:parent() then - local _, _, start = match.node:start() - local _, _, end_ = match.node:end_() - return start >= search_start and end_ >= node_end - end - end - local function scoring_function(match) - local _, _, node_start = match.node:start() - return -node_start - end - - local next_node = queries.find_best_match(bufnr, query_string, query_group, filter_function, scoring_function) - - if next_node then - return next_node.node, next_node.metadata - end -end - -function M.previous_textobject(node, query_string, query_group, same_parent, overlapping_range_ok, bufnr) - query_group = query_group or "textobjects" - local node = node or vim.treesitter.get_node_at_cursor() - local bufnr = bufnr or api.nvim_get_current_buf() - if not node then - return - end - - local _, _, node_start = node:start() - local search_end, _ - if overlapping_range_ok then - _, _, search_end = node:end_() - search_end = search_end - 1 - else - _, _, search_end = node:start() - end - - local function filter_function(match) - if not same_parent or node:parent() == match.node:parent() then - local _, _, end_ = match.node:end_() - local _, _, start = match.node:start() - return end_ <= search_end and start < node_start - end - end - - local function scoring_function(match) - local _, _, node_end = match.node:end_() - return node_end - end - - local previous_node = queries.find_best_match(bufnr, query_string, query_group, filter_function, scoring_function) - - if previous_node then - return previous_node.node, previous_node.metadata - end -end - -return M diff --git a/lua/nvim-treesitter/textobjects/swap.lua b/lua/nvim-treesitter/textobjects/swap.lua deleted file mode 100644 index ece65d61..00000000 --- a/lua/nvim-treesitter/textobjects/swap.lua +++ /dev/null @@ -1,66 +0,0 @@ -local ts_utils = require "nvim-treesitter.ts_utils" -local shared = require "nvim-treesitter.textobjects.shared" -local attach = require "nvim-treesitter.textobjects.attach" - -local M = {} - -local function swap_textobject(query_strings_regex, query_group, direction) - query_strings_regex = shared.make_query_strings_table(query_strings_regex) - query_group = query_group or "textobjects" - - local query_strings = shared.get_query_strings_from_regex(query_strings_regex, query_group) - - local bufnr, textobject_range, node, query_string - for _, query_string_iter in ipairs(query_strings) do - bufnr, textobject_range, node = shared.textobject_at_point(query_string_iter, query_group) - if node then - query_string = query_string_iter - break - end - end - if not query_string then - return - end - - local step = direction > 0 and 1 or -1 - local overlapping_range_ok = false - local same_parent = true - for _ = 1, math.abs(direction), step do - local forward = direction > 0 - local adjacent, metadata = - shared.get_adjacent(forward, node, query_string, query_group, same_parent, overlapping_range_ok, bufnr) - ts_utils.swap_nodes(textobject_range, metadata and metadata.range or adjacent, bufnr, "yes, set cursor!") - end -end - -function M.swap_next(query_strings_regex, query_group) - swap_textobject(query_strings_regex, query_group, 1) -end - -function M.swap_previous(query_strings_regex, query_group) - swap_textobject(query_strings_regex, query_group, -1) -end - -local normal_mode_functions = { "swap_next", "swap_previous" } - -M.attach = attach.make_attach(normal_mode_functions, "swap", "n", { dot_repeatable = true }) -M.detach = attach.make_detach "swap" - -M.commands = { - TSTextobjectSwapNext = { - run = M.swap_next, - args = { - "-nargs=1", - "-complete=custom,nvim_treesitter_textobjects#available_textobjects", - }, - }, - TSTextobjectSwapPrevious = { - run = M.swap_previous, - args = { - "-nargs=1", - "-complete=custom,nvim_treesitter_textobjects#available_textobjects", - }, - }, -} - -return M diff --git a/plugin/nvim-treesitter-textobjects.vim b/plugin/nvim-treesitter-textobjects.vim deleted file mode 100644 index d975a8db..00000000 --- a/plugin/nvim-treesitter-textobjects.vim +++ /dev/null @@ -1,3 +0,0 @@ -lua << EOF -require "nvim-treesitter-textobjects".init() -EOF diff --git a/queries/apex/textobjects.scm b/queries/apex/textobjects.scm index 03c04a85..8ff2295b 100644 --- a/queries/apex/textobjects.scm +++ b/queries/apex/textobjects.scm @@ -7,12 +7,8 @@ body: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (constructor_declaration) @function.outer @@ -20,12 +16,8 @@ body: (constructor_body . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (for_statement body: (_)? @loop.inner) @loop.outer @@ -59,39 +51,31 @@ arguments: (argument_list . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) ; parameters (formal_parameters - "," @_start + "," @parameter.outer . - (formal_parameter) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (formal_parameter) @parameter.inner @parameter.outer) (formal_parameters . - (formal_parameter) @parameter.inner + (formal_parameter) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (argument_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (argument_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) [ (line_comment) diff --git a/queries/bash/textobjects.scm b/queries/bash/textobjects.scm index 0adb55a5..58b0a43e 100644 --- a/queries/bash/textobjects.scm +++ b/queries/bash/textobjects.scm @@ -4,12 +4,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (case_statement) @conditional.outer diff --git a/queries/c/textobjects.scm b/queries/c/textobjects.scm index 5820616b..c4bcb787 100644 --- a/queries/c/textobjects.scm +++ b/queries/c/textobjects.scm @@ -1,8 +1,3 @@ -; TODO: supported by official Tree-sitter if (_)* is more than one node -; Neovim: will only match if (_) is exactly one node -;(function_definition -;body: (compound_statement -;("{" (_)* @function.inner "}"))?) @function.outer (declaration declarator: (function_declarator)) @function.outer @@ -13,12 +8,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (struct_specifier body: (_) @class.inner) @class.outer @@ -31,24 +22,16 @@ consequence: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end))) @conditional.outer + _+ @conditional.inner + "}")) @conditional.outer (if_statement alternative: (else_clause (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end)))) @conditional.outer + _+ @conditional.inner + "}"))) @conditional.outer (if_statement) @conditional.outer @@ -74,12 +57,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer (for_statement) @loop.outer @@ -87,12 +66,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer (do_statement) @loop.outer @@ -100,12 +75,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer (compound_statement) @block.outer @@ -117,12 +88,8 @@ arguments: (argument_list . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) (return_statement (_)? @return.inner) @return.outer @@ -145,31 +112,27 @@ (preproc_else (_) @statement.outer) -((parameter_list - "," @_start +(parameter_list + "," @parameter.outer . - (parameter_declaration) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (parameter_declaration) @parameter.inner @parameter.outer) -((parameter_list +(parameter_list . - (parameter_declaration) @parameter.inner + (parameter_declaration) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((argument_list - "," @_start +(argument_list + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((argument_list +(argument_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (number_literal) @number.inner diff --git a/queries/c_sharp/textobjects.scm b/queries/c_sharp/textobjects.scm index 4f9f968c..0366ec80 100644 --- a/queries/c_sharp/textobjects.scm +++ b/queries/c_sharp/textobjects.scm @@ -2,131 +2,61 @@ body: (declaration_list . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) @class.outer - -(class_declaration - body: (declaration_list - . - "{" - . + _* @class.inner "}")) @class.outer (struct_declaration body: (declaration_list . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) @class.outer - -(struct_declaration - body: (declaration_list - . - "{" - . + _* @class.inner "}")) @class.outer (record_declaration body: (declaration_list . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) @class.outer - -(record_declaration - body: (declaration_list - . - "{" - . - "}")?) @class.outer - -(interface_declaration - body: (declaration_list - . - "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) @class.outer + _* @class.inner + "}")) @class.outer (interface_declaration body: (declaration_list . "{" - . + _+ @class.inner "}")) @class.outer (enum_declaration body: (enum_member_declaration_list . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) @class.outer - -(enum_declaration - body: (enum_member_declaration_list - . - "{" - . + _* @class.inner "}")) @class.outer (method_declaration body: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) @function.outer + _+ @function.inner + "}")) @function.outer (method_declaration body: (arrow_expression_clause - . - (_) @_start @_end - (_)? @_end - (#make-range! "function.inner" @_start @_end))) @function.outer + _+ @function.inner)) @function.outer (constructor_declaration body: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) @function.outer + _+ @function.inner + "}")) @function.outer (lambda_expression body: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) @function.outer + _+ @function.inner + "}")) @function.outer ; loops (for_statement @@ -156,43 +86,35 @@ arguments: (argument_list . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) ; blocks (_ (block) @block.inner) @block.outer ; parameters -((parameter_list - "," @_start +(parameter_list + "," @parameter.outer . - (parameter) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (parameter) @parameter.inner @parameter.outer) -((parameter_list +(parameter_list . - (parameter) @parameter.inner + (parameter) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((argument_list - "," @_start +(argument_list + "," @parameter.outer . - (argument) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (argument) @parameter.inner @parameter.outer) -((argument_list +(argument_list . - (argument) @parameter.inner + (argument) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; comments (comment) @comment.outer diff --git a/queries/cmake/textobjects.scm b/queries/cmake/textobjects.scm index 70d2b459..684b22aa 100644 --- a/queries/cmake/textobjects.scm +++ b/queries/cmake/textobjects.scm @@ -3,49 +3,30 @@ (function_def . (function_command) - . - (_)? @_start - (_) @_end - . - (endfunction_command) - . - (#make-range! "function.inner" @_start @_end)) + _+ @function.inner + (endfunction_command) .) (if_condition) @conditional.outer (if_condition . (if_command) - . - (_)? @_start - (_) @_end - . - (endif_command) - . - (#make-range! "conditional.inner" @_start @_end)) + _+ @conditional.inner + (endif_command) .) (foreach_loop) @loop.outer (foreach_loop . (foreach_command) - . - (_)? @_start - (_) @_end - . - (endforeach_command) - . - (#make-range! "loop.inner" @_start @_end)) + _+ @loop.inner + (endforeach_command) .) (normal_command) @call.outer (normal_command "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end)) + _+ @call.inner + ")") (line_comment) @comment.outer diff --git a/queries/cpp/textobjects.scm b/queries/cpp/textobjects.scm index adc6cdbf..e85db7c7 100644 --- a/queries/cpp/textobjects.scm +++ b/queries/cpp/textobjects.scm @@ -13,12 +13,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) + _+ @loop.inner + "}")) (template_declaration (function_definition)) @function.outer @@ -29,70 +25,60 @@ (template_declaration (class_specifier)) @class.outer -((lambda_capture_specifier - "," @_start +(lambda_capture_specifier + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((lambda_capture_specifier +(lambda_capture_specifier . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((template_argument_list - "," @_start +(template_argument_list + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((template_argument_list +(template_argument_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((template_parameter_list - "," @_start +(template_parameter_list + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((template_parameter_list +(template_parameter_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((parameter_list - "," @_start +(parameter_list + "," @parameter.outer . - (optional_parameter_declaration) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (optional_parameter_declaration) @parameter.inner @parameter.outer) -((parameter_list +(parameter_list . - (optional_parameter_declaration) @parameter.inner + (optional_parameter_declaration) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((initializer_list - "," @_start +(initializer_list + "," @parameter.outer . - (_) @parameter.inner @_end) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((initializer_list +(initializer_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (new_expression (argument_list) @call.inner) @call.outer diff --git a/queries/css/textobjects.scm b/queries/css/textobjects.scm index 4d132431..55e6807d 100644 --- a/queries/css/textobjects.scm +++ b/queries/css/textobjects.scm @@ -8,13 +8,8 @@ (property_name) @assignment.lhs . ":" - . - (_) @_start - (_)? @_end - . - ";" - (#make-range! "assignment.inner" @_start @_end) - (#make-range! "assignment.rhs" @_start @_end)) @assignment.outer + _+ @assignment.inner @assignment.rhs + ";") @assignment.outer (declaration (property_name) @assignment.inner) diff --git a/queries/dart/textobjects.scm b/queries/dart/textobjects.scm index ebe535d9..d4a91257 100644 --- a/queries/dart/textobjects.scm +++ b/queries/dart/textobjects.scm @@ -1,9 +1,8 @@ ; class -(((annotation)? @class.outer +((annotation)? @class.outer . (class_definition - body: (class_body) @_end @class.inner) @_start) - (#make-range! "class.outer" @_start @_end)) + body: (class_body) @class.inner) @class.outer) (mixin_declaration (class_body) @class.inner) @class.outer @@ -15,26 +14,21 @@ body: (extension_body) @class.inner) @class.outer ; function/method -(((annotation)? @function.outer +((annotation)? @function.outer . [ (method_signature) (function_signature) - ] @_start + ] @function.outer . - (function_body) @_end) - (#make-range! "function.outer" @_start @_end)) + (function_body) @function.outer) (function_body (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (type_alias (function_type)? @function.inner) @function.outer @@ -46,44 +40,39 @@ (type_parameter) ] @parameter.inner -("," @_start +("," @parameter.outer . [ (formal_parameter) (normal_parameter_type) (type_parameter) - ] @_par - (#make-range! "parameter.outer" @_start @_par)) + ] @parameter.outer) ([ (formal_parameter) (normal_parameter_type) (type_parameter) -] @_par +] @parameter.outer . - "," @_end - (#make-range! "parameter.outer" @_par @_end)) + "," @parameter.outer) ; TODO: (_)* not supported yet -> for now this works correctly only with simple arguments -((arguments +(arguments . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((arguments - "," @_start +(arguments + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) ; call -((identifier) @_start +((identifier) @call.outer . (selector - (argument_part) @_end) - (#make-range! "call.outer" @_start @_end)) + (argument_part) @call.outer)) ((identifier) . @@ -92,12 +81,8 @@ (arguments . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))))) + _+ @call.inner + ")")))) ; block (block) @block.outer diff --git a/queries/ecma/textobjects.scm b/queries/ecma/textobjects.scm index c274990e..f84acc8f 100644 --- a/queries/ecma/textobjects.scm +++ b/queries/ecma/textobjects.scm @@ -8,23 +8,15 @@ body: (statement_block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (function_expression body: (statement_block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (export_statement (function_declaration)) @function.outer @@ -36,12 +28,8 @@ body: (statement_block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (method_definition body: (statement_block)) @function.outer @@ -50,12 +38,8 @@ body: (statement_block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (class_declaration body: (class_body) @class.inner) @class.outer @@ -67,68 +51,44 @@ body: (statement_block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer (for_statement body: (statement_block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer (while_statement body: (statement_block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer (do_statement body: (statement_block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer (if_statement consequence: (statement_block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end))) @conditional.outer + _+ @conditional.inner + "}")) @conditional.outer (if_statement alternative: (else_clause (statement_block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end)))) @conditional.outer + _+ @conditional.inner + "}"))) @conditional.outer (if_statement) @conditional.outer @@ -141,25 +101,16 @@ arguments: (arguments . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) -((new_expression - constructor: (identifier) @_cons +(new_expression + constructor: (identifier) @call.outer arguments: (arguments . "(" - . - (_) @_start - (_)? @_end - . - ")") @_args) - (#make-range! "call.outer" @_cons @_args) - (#make-range! "call.inner" @_start @_end)) + _+ @call.inner + ")") @call.outer) ; blocks (_ @@ -170,17 +121,15 @@ ; function ([ x ]) ... ; function (v = default_value) (formal_parameters - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (formal_parameters . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; If the array/object pattern is the first parameter, treat its elements as the argument list (formal_parameters @@ -188,15 +137,14 @@ (_ [ (object_pattern - "," @_start + "," @parameter.outer . - (_) @parameter.inner) + (_) @parameter.inner @parameter.outer) (array_pattern - "," @_start + "," @parameter.outer . - (_) @parameter.inner) - ]) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) + ])) (formal_parameters . @@ -204,30 +152,27 @@ [ (object_pattern . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) + ","? @parameter.outer) (array_pattern . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - ]) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) + ])) ; arguments (arguments - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (arguments . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; comment (comment) @comment.outer diff --git a/queries/elixir/textobjects.scm b/queries/elixir/textobjects.scm index d6e72d28..9475136e 100644 --- a/queries/elixir/textobjects.scm +++ b/queries/elixir/textobjects.scm @@ -2,19 +2,15 @@ ([ (do_block "do" - . - (_) @_do - (_) @_end - . + _+ @block.inner "end") (do_block "do" . - ((_) @_do) @_end + ((_) @block.inner) @block.inner . "end") -] - (#make-range! "block.inner" @_do @_end)) @block.outer +]) @block.outer ; Class Objects (Modules, Protocols) ; multiple children @@ -25,12 +21,8 @@ (alias)) (do_block "do" - . - (_) @_do - (_) @_end - . - "end") - (#make-range! "class.inner" @_do @_end)) @class.outer + _+ @class.inner + "end")) @class.outer ; single child match (call @@ -58,41 +50,35 @@ (call [ (arguments - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - "," @_delimiter) + "," @parameter.outer) (arguments - ((_) @parameter.inner) @_delimiter .) - ] - (#make-range! "parameter.outer" @parameter.inner @_delimiter)) + ((_) @parameter.inner @parameter.outer) @parameter.outer .) + ]) (binary_operator left: (call [ (arguments - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - "," @_delimiter) + "," @parameter.outer) (arguments - ((_) @parameter.inner) @_delimiter .) - ] - (#make-range! "parameter.outer" @parameter.inner @_delimiter))) + ((_) @parameter.inner @parameter.outer) @parameter.outer .) + ])) ]) [ (do_block "do" - . - (_) @_do - (_) @_end - . + _+ @function.inner "end") (do_block "do" . - ((_) @_do) @_end + ((_) @function.inner) @function.inner . "end") - ] - (#make-range! "function.inner" @_do @_end)) @function.outer + ]) @function.outer (call target: ((identifier) @_identifier @@ -106,19 +92,15 @@ [ (do_block "do" - . - (_) @_do - (_) @_end - . + _+ @function.inner "end") (do_block "do" . - ((_) @_do) @_end + ((_) @function.inner) @function.inner . "end") - ] - (#make-range! "function.inner" @_do @_end)) @function.outer + ]) @function.outer (call target: ((identifier) @_identifier @@ -128,24 +110,22 @@ (call [ (arguments - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - "," @_delimiter) + "," @parameter.outer) (arguments - ((_) @parameter.inner) @_delimiter .) - ] - (#make-range! "parameter.outer" @parameter.inner @_delimiter)) + ((_) @parameter.inner @parameter.outer) @parameter.outer .) + ]) (binary_operator left: (call [ (arguments - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - "," @_delimiter) + "," @parameter.outer) (arguments - ((_) @parameter.inner) @_delimiter .) - ] - (#make-range! "parameter.outer" @parameter.inner @_delimiter))) + ((_) @parameter.inner @parameter.outer) @parameter.outer .) + ])) ] (keywords (pair diff --git a/queries/elm/textobjects.scm b/queries/elm/textobjects.scm index 5bb0f085..c7d1abe4 100644 --- a/queries/elm/textobjects.scm +++ b/queries/elm/textobjects.scm @@ -36,43 +36,37 @@ ; Parameters ; type annotations -((type_expression - (arrow) @_start +(type_expression + (arrow) @parameter.outer . - (type_ref) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (type_ref) @parameter.inner @parameter.outer) -((type_expression +(type_expression . - (type_ref) @parameter.inner + (type_ref) @parameter.inner @parameter.outer . - (arrow)? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + (arrow)? @parameter.outer) ; list items -((list_expr - "," @_start +(list_expr + "," @parameter.outer . - exprList: (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + exprList: (_) @parameter.inner @parameter.outer) -((list_expr +(list_expr . - exprList: (_) @parameter.inner + exprList: (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; tuple items -((tuple_expr - "," @_start +(tuple_expr + "," @parameter.outer . - expr: (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + expr: (_) @parameter.inner @parameter.outer) -((tuple_expr +(tuple_expr . - expr: (_) @parameter.inner + expr: (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) diff --git a/queries/fennel/textobjects.scm b/queries/fennel/textobjects.scm index 32367815..599bab1f 100644 --- a/queries/fennel/textobjects.scm +++ b/queries/fennel/textobjects.scm @@ -9,60 +9,62 @@ ; functions ; NOTE: Doesn't capture the comments before the first `item` field -([ - (fn_form - [ - (table_metadata) - (docstring) - ] - . - item: (_) @_start - (_)? @_end - . - close: _ .) - (fn_form - args: (_) - . - item: (_) @_start - (_)? @_end - . - close: _ .) - (lambda_form - [ - (table_metadata) - (docstring) - ] - . - item: (_) @_start - (_)? @_end - . - close: _ .) - (lambda_form - args: (_) - . - item: (_) @_start - (_)? @_end - . - close: _ .) - (macro_form - [ - (table_metadata) - (docstring) - ] - . - item: (_) @_start - (_)? @_end - . - close: _ .) - (macro_form - args: (_) - . - item: (_) @_start - (_)? @_end - . - close: _ .) -] - (#make-range! "function.inner" @_start @_end)) +(fn_form + [ + (table_metadata) + (docstring) + ] + . + item: (_) @function.inner + (_)? @function.inner + . + close: _ .) + +(fn_form + args: (_) + . + item: (_) @function.inner + (_)? @function.inner + . + close: _ .) + +(lambda_form + [ + (table_metadata) + (docstring) + ] + . + item: (_) @function.inner + (_)? @function.inner + . + close: _ .) + +(lambda_form + args: (_) + . + item: (_) @function.inner + (_)? @function.inner + . + close: _ .) + +(macro_form + [ + (table_metadata) + (docstring) + ] + . + item: (_) @function.inner + (_)? @function.inner + . + close: _ .) + +(macro_form + args: (_) + . + item: (_) @function.inner + (_)? @function.inner + . + close: _ .) [ (fn_form) @@ -77,12 +79,11 @@ ; call (list call: (symbol) @_fn_name - item: (_) @_start - (_) @_end + item: (_) @call.inner + (_) @call.inner . close: _ - (#not-any-of? @_fn_name "do" "while" "when") - (#make-range! "call.inner" @_start @_end)) @call.outer + (#not-any-of? @_fn_name "do" "while" "when")) @call.outer ; assignment (local_form @@ -128,78 +129,50 @@ ; loops (each_form iter_body: (_) - . - (_) @_start - (_)? @_end - . - close: _ - (#make-range! "loop.inner" @_start @_end)) + _+ @loop.inner + close: _) (each_form) @loop.outer (collect_form iter_body: (_) - . - (_) @_start - (_)? @_end - . - close: _ - (#make-range! "loop.inner" @_start @_end)) + _+ @loop.inner + close: _) (collect_form) @loop.outer (icollect_form iter_body: (_) - . - (_) @_start - (_)? @_end - . - close: _ - (#make-range! "loop.inner" @_start @_end)) + _+ @loop.inner + close: _) (icollect_form) @loop.outer (accumulate_form iter_body: (_) - . - (_) @_start - (_)? @_end - . - close: _ - (#make-range! "loop.inner" @_start @_end)) + _+ @loop.inner + close: _) (accumulate_form) @loop.outer (for_form iter_body: (_) - . - (_) @_start - (_)? @_end - . - close: _ - (#make-range! "loop.inner" @_start @_end)) + _+ @loop.inner + close: _) (for_form) @loop.outer (fcollect_form iter_body: (_) - . - (_) @_start - (_)? @_end - . - close: _ - (#make-range! "loop.inner" @_start @_end)) + _+ @loop.inner + close: _) (fcollect_form) @loop.outer (faccumulate_form iter_body: (_) - . - (_) @_start - (_)? @_end - . - close: _ - (#make-range! "loop.inner" @_start @_end)) + _+ @loop.inner + close: _) (faccumulate_form) @loop.outer diff --git a/queries/fish/textobjects.scm b/queries/fish/textobjects.scm index dc2e6136..58a6b3d8 100644 --- a/queries/fish/textobjects.scm +++ b/queries/fish/textobjects.scm @@ -28,12 +28,12 @@ ; comment ; leave space after comment marker if there is one ((comment) @comment.inner @comment.outer - (#offset! @comment.inner 0 2 0) + (#offset! @comment.inner 0 2 0 0) (#lua-match? @comment.outer "# .*")) ; else remove everything accept comment marker ((comment) @comment.inner @comment.outer - (#offset! @comment.inner 0 1 0)) + (#offset! @comment.inner 0 1 0 0)) ; conditional (if_statement diff --git a/queries/foam/textobjects.scm b/queries/foam/textobjects.scm index d92d8eb6..39b32ed3 100644 --- a/queries/foam/textobjects.scm +++ b/queries/foam/textobjects.scm @@ -2,17 +2,14 @@ (dict_core) @class.inner -((key_value - value: _? @_start - (_)* - _? @parameter.inner) - (#make-range! "function.inner" @_start @parameter.inner)) @function.outer +(key_value + value: _? @function.inner + (_)* @function.inner + _? @parameter.inner @function.inner) @function.outer (code (_)* @class.inner) @class.outer -((comment) @_start - (comment)+ @_end - (#make-range! "comment.outer" @_start @_end)) +(comment)+ @comment.outer (comment) @comment.inner diff --git a/queries/gdscript/textobjects.scm b/queries/gdscript/textobjects.scm index 3fd97199..def4bc97 100644 --- a/queries/gdscript/textobjects.scm +++ b/queries/gdscript/textobjects.scm @@ -31,40 +31,34 @@ (comment) @comment.outer (parameters - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (parameters . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (arguments - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (arguments . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (array - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (array . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) diff --git a/queries/glimmer/textobjects.scm b/queries/glimmer/textobjects.scm index 6bfdc303..76dc44f5 100644 --- a/queries/glimmer/textobjects.scm +++ b/queries/glimmer/textobjects.scm @@ -30,23 +30,15 @@ . (block_statement_end)) -((element_node +(element_node (element_node_start) - . - (_) @_start - (_) @_end - . + _+ @function.inner (element_node_end)) - (#make-range! "function.inner" @_start @_end)) -((block_statement +(block_statement (block_statement_start) - . - (_) @_start - (_) @_end - . + _+ @function.inner (block_statement_end)) - (#make-range! "function.inner" @_start @_end)) (mustache_statement . diff --git a/queries/go/textobjects.scm b/queries/go/textobjects.scm index 719505bf..ce117495 100644 --- a/queries/go/textobjects.scm +++ b/queries/go/textobjects.scm @@ -3,36 +3,24 @@ body: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) ; inner function literals (func_literal body: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) ; method as inner function textobject (method_declaration body: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) ; outer function textobject (function_declaration) @function.outer @@ -99,26 +87,20 @@ arguments: (argument_list . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) ; parameters (parameter_list - "," @_start + "," @parameter.outer . - (parameter_declaration) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (parameter_declaration) @parameter.inner @parameter.outer) (parameter_list . - (parameter_declaration) @parameter.inner + (parameter_declaration) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (parameter_declaration name: (identifier) @@ -129,24 +111,21 @@ type: (_)) @parameter.inner (parameter_list - "," @_start + "," @parameter.outer . - (variadic_parameter_declaration) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (variadic_parameter_declaration) @parameter.inner @parameter.outer) ; arguments (argument_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (argument_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; assignments (short_var_declaration diff --git a/queries/haskell/textobjects.scm b/queries/haskell/textobjects.scm index cacdc4af..a4ef43d3 100644 --- a/queries/haskell/textobjects.scm +++ b/queries/haskell/textobjects.scm @@ -1,13 +1,7 @@ -((apply +(apply . function: (_) - . - (_) @_start - . - (_)* - . - (_)? @_end .) - (#make-range! "call.inner" @_start @_end)) @call.outer + _+ @call.inner) @call.outer (infix (_) @@ -22,23 +16,18 @@ (decl/function patterns: (_) - . - match: (_) @_start - match: (_)? @_end - . - (#make-range! "function.inner" @_start @_end)) + match: _+ @function.inner) ; also treat function signature as @function.outer (signature) @function.outer ; treat signature with function as @function.outer (((decl/signature - name: (_) @_sig_name) @_start + name: (_) @_sig_name) @function.outer . (decl/function - name: (_) @_func_name) @_end) - (#eq? @_sig_name @_func_name) - (#make-range! "function.outer" @_start @_end)) + name: (_) @_func_name) @function.outer) + (#eq? @_sig_name @_func_name)) (class) @class.outer diff --git a/queries/hcl/textobjects.scm b/queries/hcl/textobjects.scm index 6e20dc59..91367b48 100644 --- a/queries/hcl/textobjects.scm +++ b/queries/hcl/textobjects.scm @@ -54,15 +54,13 @@ (numeric_lit) @number.inner -((function_arguments - "," @_start +(function_arguments + "," @parameter.outer . - (expression) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (expression) @parameter.inner @parameter.outer) -((function_arguments +(function_arguments . - (expression) @parameter.inner + (expression) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) diff --git a/queries/heex/textobjects.scm b/queries/heex/textobjects.scm index a31e83bd..6cbe806b 100644 --- a/queries/heex/textobjects.scm +++ b/queries/heex/textobjects.scm @@ -11,11 +11,7 @@ (attribute) @attribute.outer -((tag +(tag (start_tag) - . - (_) @_start - (_) @_end - . + _+ @function.inner (end_tag)) - (#make-range! "function.inner" @_start @_end)) diff --git a/queries/html/textobjects.scm b/queries/html/textobjects.scm index 51bc4f33..e60f9cdf 100644 --- a/queries/html/textobjects.scm +++ b/queries/html/textobjects.scm @@ -11,14 +11,10 @@ (attribute) @attribute.outer -((element +(element (start_tag) - . - (_) @_start - (_) @_end - . + _+ @function.inner (end_tag)) - (#make-range! "function.inner" @_start @_end)) (script_element) @function.outer @@ -55,12 +51,8 @@ ((element (start_tag (tag_name) @_tag) - . - (_) @_start - (_) @_end - . + _+ @class.inner (end_tag)) - (#match? @_tag "^(html|section|h[0-9]|header|title|head|body)$") - (#make-range! "class.inner" @_start @_end)) + (#match? @_tag "^(html|section|h[0-9]|header|title|head|body)$")) (comment) @comment.outer diff --git a/queries/inko/textobjects.scm b/queries/inko/textobjects.scm index 4f8326f3..f1112484 100644 --- a/queries/inko/textobjects.scm +++ b/queries/inko/textobjects.scm @@ -5,12 +5,8 @@ body: (class_body . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) ; Traits (trait) @class.outer @@ -19,12 +15,8 @@ body: (trait_body . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) ; Implementations (implement_trait) @class.outer @@ -33,12 +25,8 @@ body: (implement_trait_body . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (reopen_class) @class.outer @@ -46,12 +34,8 @@ body: (reopen_class_body . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) ; Methods and closures (method) @function.outer @@ -60,12 +44,8 @@ body: (block . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (closure) @function.outer @@ -73,24 +53,16 @@ body: (block . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) ; Loops (while body: (block . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer (while condition: (_) @conditional.inner) @@ -99,12 +71,8 @@ body: (block . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer ; Conditionals (if @@ -132,96 +100,80 @@ arguments: (arguments . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) (return (_)? @return.inner) @return.outer ; Call and type arguments -((arguments - "," @_start +(arguments + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((arguments +(arguments . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((type_arguments - "," @_start +(type_arguments + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((type_arguments +(type_arguments . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; Patterns -((class_pattern - "," @_start +(class_pattern + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((class_pattern +(class_pattern . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((tuple_pattern - "," @_start +(tuple_pattern + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((tuple_pattern +(tuple_pattern . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; Sequence types (tuple - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (tuple . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (array - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (array . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; Blocks (block diff --git a/queries/java/textobjects.scm b/queries/java/textobjects.scm index 5a16b35c..e3a9e278 100644 --- a/queries/java/textobjects.scm +++ b/queries/java/textobjects.scm @@ -7,12 +7,8 @@ body: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (constructor_declaration) @function.outer @@ -20,12 +16,8 @@ body: (constructor_body . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (for_statement body: (_)? @loop.inner) @loop.outer @@ -59,39 +51,31 @@ arguments: (argument_list . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) ; parameters (formal_parameters - "," @_start + "," @parameter.outer . - (formal_parameter) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (formal_parameter) @parameter.inner @parameter.outer) (formal_parameters . - (formal_parameter) @parameter.inner + (formal_parameter) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (argument_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (argument_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) [ (line_comment) diff --git a/queries/julia/textobjects.scm b/queries/julia/textobjects.scm index efcaa0df..96cc03eb 100644 --- a/queries/julia/textobjects.scm +++ b/queries/julia/textobjects.scm @@ -1,27 +1,24 @@ ; Blocks (compound_statement) @block.outer -((compound_statement +(compound_statement . - (_) @_start - (_)? @_end .) - (#make-range! "block.inner" @_start @_end)) + (_) @block.inner + (_)? @block.inner .) (quote_statement) @block.outer -((quote_statement +(quote_statement . - (_) @_start - (_)? @_end .) - (#make-range! "block.inner" @_start @_end)) + (_) @block.inner + (_)? @block.inner .) (let_statement) @block.outer -((let_statement +(let_statement . - (_) @_start - (_)? @_end .) - (#make-range! "block.inner" @_start @_end)) + (_) @block.inner + (_)? @block.inner .) ; Conditionals (if_statement @@ -34,74 +31,66 @@ ((if_statement condition: (_) . - (_) @_start - (_)? @_end + (_) @conditional.inner + (_)? @conditional.inner . [ "end" (elseif_clause) (else_clause) - ]) - (#make-range! "conditional.inner" @_start @_end)) @conditional.outer - -((elseif_clause - condition: (_) - . - (_) @_start - (_)? @_end .) - (#make-range! "conditional.inner" @_start @_end)) + ]) @conditional.outer + (elseif_clause + condition: (_) + . + (_) @conditional.inner + (_)? @conditional.inner .)) -((else_clause +(else_clause . - (_) @_start - (_)? @_end .) - (#make-range! "conditional.inner" @_start @_end)) + (_) @conditional.inner + (_)? @conditional.inner .) ; Loops (for_statement) @loop.outer -((for_statement +(for_statement . - (_) @_start - (_)? @_end .) - (#make-range! "loop.inner" @_start @_end)) + (_) @loop.inner + (_)? @loop.inner .) (while_statement condition: (_) @loop.inner) @loop.outer -((while_statement +(while_statement condition: (_) . - (_) @_start - (_)? @_end .) - (#make-range! "loop.inner" @_start @_end)) + (_) @loop.inner + (_)? @loop.inner .) ; Type definitions (struct_definition) @class.outer -((struct_definition - name: (_) +(struct_definition + (type_head) . - (_) @_start - (_)? @_end .) - (#make-range! "class.inner" @_start @_end)) + (_) @class.inner + (_)? @class.inner .) ; Function definitions (function_definition) @function.outer -((function_definition +(function_definition (signature) . - (_) @_start - (_)? @_end .) - (#make-range! "function.inner" @_start @_end)) + (_) @function.inner + (_)? @function.inner .) (assignment (call_expression) (operator) (_) @function.inner) @function.outer -(function_expression +(arrow_function_expression [ (identifier) (argument_list) @@ -111,12 +100,11 @@ (macro_definition) @function.outer -((macro_definition +(macro_definition (signature) . - (_) @_start - (_)? @_end .) - (#make-range! "function.inner" @_start @_end)) + (_) @function.inner + (_)? @function.inner .) ; Calls (call_expression) @call.outer @@ -126,11 +114,10 @@ . "(" . - (_) @_start - (_)? @_end + (_) @call.inner + (_)? @call.inner . - ")" - (#make-range! "call.inner" @_start @_end))) + ")")) (macrocall_expression) @call.outer @@ -139,11 +126,10 @@ . "(" . - (_) @_start - (_)? @_end + (_) @call.inner + (_)? @call.inner . - ")" - (#make-range! "call.inner" @_start @_end))) + ")")) (broadcast_call_expression) @call.outer @@ -152,69 +138,61 @@ . "(" . - (_) @_start - (_)? @_end + (_) @call.inner + (_)? @call.inner . - ")" - (#make-range! "call.inner" @_start @_end))) + ")")) ; Parameters ((argument_list [ "," ";" - ] @_start + ] @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) - -((argument_list - (_) @parameter.inner - . - [ - "," - ";" - ] @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + (_) @parameter.inner @parameter.outer) + (argument_list + (_) @parameter.inner @parameter.outer + . + [ + "," + ";" + ] @parameter.outer)) -((tuple_expression +(tuple_expression [ "," ";" - ] @_start + ] @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((tuple_expression +(tuple_expression "(" . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . [ "," ";" - ]? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ]? @parameter.outer) -((vector_expression +(vector_expression [ "," ";" - ] @_start + ] @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((vector_expression +(vector_expression . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . [ "," ";" - ]? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ]? @parameter.outer) ; Assignment (assignment diff --git a/queries/latex/textobjects.scm b/queries/latex/textobjects.scm index 1bdcaa5f..619d2e42 100644 --- a/queries/latex/textobjects.scm +++ b/queries/latex/textobjects.scm @@ -1,30 +1,16 @@ -((generic_environment - begin: (_) - . - (_) @_start - (_)? @_end - . - end: (_)) @block.outer - (#make-range! "block.inner" @_start @_end)) - -((math_environment - begin: (_) - . - (_) @_start - (_)? @_end - . - end: (_)) @block.outer - (#make-range! "block.inner" @_start @_end)) - (generic_environment - begin: (begin - name: (curly_group_text - text: (text) @frame.inner))) @frame.outer + . + (_) + _+ @block.inner + (_) .) @block.outer -(math_environment - begin: (begin +((generic_environment + (begin name: (curly_group_text - text: (text) @frame.inner))) @frame.outer + (text) @_frame)) + _+ @frame.inner + (_) .) @frame.outer + (#eq? @_frame "frame")) [ (generic_command) @@ -34,68 +20,60 @@ (text_mode (curly_group "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "call.inner" @_start @_end)) + _+ @call.inner + "}")) (generic_command (curly_group "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "call.inner" @_start @_end)) - -((part + _+ @call.inner + "}")) + +(part text: (_) - . - (_) @_start - (_)? @_end .) @class.outer - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner) + +(part + text: (_)) @class.outer -((chapter +(chapter text: (_) - . - (_) @_start - (_)? @_end .) @class.outer - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner) + +(chapter + text: (_)) @class.outer -((section +(section text: (_) - . - (_) @_start - (_)? @_end .) @class.outer - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner) -((subsection +(section + text: (_)) @class.outer + +(subsection text: (_) - . - (_) @_start - (_)? @_end .) @class.outer - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner) + +(subsection + text: (_)) @class.outer -((subsubsection +(subsubsection text: (_) - . - (_) @_start - (_)? @_end .) @class.outer - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner) + +(subsubsection + text: (_)) @class.outer -((paragraph +(paragraph text: (_) - . - (_) @_start - (_)? @_end .) @class.outer - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner) -((subparagraph +(paragraph + text: (_)) @class.outer + +(subparagraph text: (_) - . - (_) @_start - (_)? @_end .) @class.outer - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner) + +(subparagraph + text: (_)) @class.outer diff --git a/queries/lua/textobjects.scm b/queries/lua/textobjects.scm index fa1b77db..d5c59059 100644 --- a/queries/lua/textobjects.scm +++ b/queries/lua/textobjects.scm @@ -13,12 +13,8 @@ arguments: (arguments . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) ; class ; comment @@ -71,34 +67,29 @@ ; parameter (arguments . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (parameters . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (table_constructor - (field) @parameter.inner - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + (field) @parameter.inner @parameter.outer + ","? @parameter.outer) (arguments - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (parameters - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) ; number (number) @number.inner diff --git a/queries/matlab/textobjects.scm b/queries/matlab/textobjects.scm index 39e254f5..e2e6ee97 100644 --- a/queries/matlab/textobjects.scm +++ b/queries/matlab/textobjects.scm @@ -10,17 +10,15 @@ (function_call (arguments)? @call.inner) @call.outer -((arguments - ","? @_start +(arguments + ","? @parameter.outer . - (_) @parameter.inner .) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer .) -((arguments - (_) @parameter.inner +(arguments + (_) @parameter.inner @parameter.outer . - "," @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + "," @parameter.outer) (command) @call.outer @@ -28,10 +26,7 @@ (command_argument) @parameter.inner @parameter.outer) (command - (command_argument) @_start - (command_argument)* @_end - . - (#make-range! "call.inner" @_start @_end)) + (command_argument)+ @call.inner) (if_statement (block) @conditional.inner) @conditional.outer @@ -73,29 +68,25 @@ (function_output (identifier) @parameter.inner @parameter.outer) -((function_arguments - ","? @_start +(function_arguments + ","? @parameter.outer . - (_) @parameter.inner .) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer .) -((function_arguments - (_) @parameter.inner +(function_arguments + (_) @parameter.inner @parameter.outer . - "," @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + "," @parameter.outer) -((multioutput_variable - ","? @_start +(multioutput_variable + ","? @parameter.outer . - (_) @parameter.inner .) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer .) -((multioutput_variable - (_) @parameter.inner +(multioutput_variable + (_) @parameter.inner @parameter.outer . - "," @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + "," @parameter.outer) (try_statement (block) @conditional.inner) @conditional.outer @@ -128,17 +119,15 @@ left: (_) @assignment.lhs (_) @assignment.rhs) @assignment.outer -((superclasses - "&"? @_start +(superclasses + "&"? @parameter.outer . - (_) @parameter.inner .) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer .) -((superclasses - (_) @parameter.inner +(superclasses + (_) @parameter.inner @parameter.outer . - "&" @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + "&" @parameter.outer) (enum (identifier) @parameter.inner @parameter.outer) @@ -146,50 +135,42 @@ (property name: (_) @parameter.outer @parameter.inner) -((enum - ","? @_start +(enum + ","? @parameter.outer . - (_) @parameter.inner .) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer .) -((enum - (_) @parameter.inner +(enum + (_) @parameter.inner @parameter.outer . - "," @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + "," @parameter.outer) -((validation_functions - ","? @_start +(validation_functions + ","? @parameter.outer . - (_) @parameter.inner .) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer .) -((validation_functions - (_) @parameter.inner +(validation_functions + (_) @parameter.inner @parameter.outer . - "," @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + "," @parameter.outer) -((dimensions - ","? @_start +(dimensions + ","? @parameter.outer . - (_) @parameter.inner .) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer .) -((dimensions - (_) @parameter.inner +(dimensions + (_) @parameter.inner @parameter.outer . - "," @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + "," @parameter.outer) -((attributes - ","? @_start +(attributes + ","? @parameter.outer . - (_) @parameter.inner .) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer .) -((attributes - (_) @parameter.inner +(attributes + (_) @parameter.inner @parameter.outer . - "," @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + "," @parameter.outer) diff --git a/queries/nim/textobjects.scm b/queries/nim/textobjects.scm index 78f665c3..f9398bf5 100644 --- a/queries/nim/textobjects.scm +++ b/queries/nim/textobjects.scm @@ -109,9 +109,8 @@ ] @loop.outer (for - left: (_) @_start - right: (_) @_end - (#make-range! "loop.inner" @_start @_end)) + left: (_) @loop.inner + right: (_) @loop.inner) (for body: (statement_list) @loop.inner) @@ -134,85 +133,48 @@ ; @block.outer (case ":" - . - (_) @_start - (_) @_end - . - (#make-range! "block.inner" @_start @_end)) @block.outer + _+ @block.inner) @block.outer (object_declaration (field_declaration_list) @block.inner) @block.outer (tuple_type - . - (field_declaration) @_start - (field_declaration)? @_end - . - (#make-range! "block.inner" @_start @_end)) @block.outer + (field_declaration_list + . + "[" + _+ @block.inner + "]" .)) @block.outer -; BUG: @_end anchor not working correctly in all cases (enum_declaration . - (enum_field_declaration) @_start - (enum_field_declaration)? @_end + "enum" + _+ @block.inner) @block.outer + +(using_section + . + "using" + _+ @block.inner) @block.outer + +(const_section . - (#make-range! "block.inner" @_start @_end)) @block.outer + "const" + _+ @block.inner) @block.outer -; BUG: @_end anchor not working correctly in all cases -; using_section -; const_section -; let_section -; var_section -(_ +(let_section . - (variable_declaration) @_start - (variable_declaration) @_end + "let" + _+ @block.inner) @block.outer + +(var_section . - (#make-range! "block.inner" @_start @_end)) @block.outer + "var" + _+ @block.inner) @block.outer -; BUG: @_end anchor not working correctly in all cases (type_section . - (type_declaration) @_start - (type_declaration) @_end - . - (#make-range! "block.inner" @_start @_end)) @block.outer - -; BUG: @_end anchor not working correctly in all cases -; (pragma_statement) -; -; (while) -; (static_statement) -; (defer) -; -; (block) -; (if) -; (when) -; (case) -; (try) -; (for) -; -; (proc_declaration) -; (func_declaration) -; (method_declaration) -; (iterator_declaration) -; (macro_declaration) -; (template_declaration) -; (converter_declaration) -; -; (proc_expression) -; (func_expression) -; (iterator_expression) -; -; (concept_declaration) -; (of_branch) -; (elif_branch) -; (else_branch) -; (except_branch) -; (finally_branch) -; -; (do_block) -; (call) + "type" + _+ @block.inner) + (_ (statement_list) @block.inner) @block.outer @@ -224,106 +186,92 @@ [ "," ";" - ] @_start + ] @parameter.outer . - (parameter_declaration) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (parameter_declaration) @parameter.inner @parameter.outer) (parameter_declaration_list . - (parameter_declaration) @parameter.inner + (parameter_declaration) @parameter.inner @parameter.outer . [ "," ";" - ]? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ]? @parameter.outer) ; generic parameters when declaring (generic_parameter_list - "," @_start + "," @parameter.outer . - (parameter_declaration) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (parameter_declaration) @parameter.inner @parameter.outer) (generic_parameter_list . - (parameter_declaration) @parameter.inner + (parameter_declaration) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; arguments when calling (argument_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (argument_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; containers (array_construction - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (array_construction . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (tuple_construction - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (tuple_construction . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (curly_construction - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (curly_construction . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; generic arguments when calling ; subscript operator ; generic types (bracket_expression right: (argument_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer)) (bracket_expression right: (argument_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer)) ; import x,x ; import except x,x @@ -334,148 +282,128 @@ ; case of x,x ; try except x,x (expression_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (expression_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; pragmas (pragma_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (pragma_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; variable_declaration ; for ; identifier_declaration `x,y: type = value` (symbol_declaration_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (symbol_declaration_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; infix_expression (infix_expression - operator: (_) @_start - right: (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + operator: (_) @parameter.outer + right: (_) @parameter.inner @parameter.outer) (infix_expression - left: (_) @parameter.inner - operator: (_) @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + left: (_) @parameter.inner @parameter.outer + operator: (_) @parameter.outer) ; tuple_type inline (field_declaration_list [ "," ";" - ] @_start + ] @parameter.outer . - (field_declaration) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (field_declaration) @parameter.inner @parameter.outer) (field_declaration_list . - (field_declaration) @parameter.inner + (field_declaration) @parameter.inner @parameter.outer . [ "," ";" - ]? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ]? @parameter.outer) ; enum (enum_declaration - "," @_start + "," @parameter.outer . - (enum_field_declaration) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (enum_field_declaration) @parameter.inner @parameter.outer) (enum_declaration . - (enum_field_declaration) @parameter.inner + (enum_field_declaration) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; tuple_deconstruct_declaration (tuple_deconstruct_declaration - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (tuple_deconstruct_declaration . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; concept parameter list ; concept refinement list (parameter_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (parameter_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (refinement_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (refinement_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; dot_generic_call `v.call[:type, type]() (generic_argument_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (generic_argument_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; ============================================================================== ; @regex.inner @@ -501,10 +429,9 @@ ; @assignment.lhs ; @assignment.rhs (variable_declaration - (symbol_declaration_list) @_symbols - type: (type_expression)? @_type - value: (_) @assignment.rhs @assignment.inner - (#make-range! "assignment.lhs" @_symbols @_type)) @assignment.outer + (symbol_declaration_list) @assignment.lhs + type: (type_expression)? @assignment.lhs + value: (_) @assignment.rhs @assignment.inner) @assignment.outer (type_declaration (type_symbol_declaration) @assignment.lhs @@ -534,10 +461,9 @@ ; object declaration fields ; tuple declaration fields (field_declaration - (symbol_declaration_list) @_symbols - type: (type_expression)? @_type - value: (_)? @assignment.rhs @assignment.inner - (#make-range! "assignment.lhs" @_symbols @_type)) @assignment.outer + (symbol_declaration_list) @assignment.lhs + type: (type_expression)? @assignment.lhs + value: (_)? @assignment.rhs @assignment.inner) @assignment.outer ; enum types (enum_field_declaration diff --git a/queries/odin/textobjects.scm b/queries/odin/textobjects.scm index b8e93c30..31efcba4 100644 --- a/queries/odin/textobjects.scm +++ b/queries/odin/textobjects.scm @@ -4,12 +4,8 @@ (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end)))) @function.outer + _+ @function.inner + "}"))) @function.outer ; returns (return_statement @@ -19,75 +15,35 @@ (member_expression (call_expression)) @call.outer -; plain call -((_ - (call_expression) @call.outer) @_parent - (#not-kind-eq? @_parent "member_expression")) - ; call arguments -((call_expression +(call_expression function: (_) . - argument: (_) @_first - argument: (_) @_last .) - (#make-range! "call.inner" @_first @_last)) + argument: (_) @call.inner + argument: (_) @call.inner .) ; block (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "block.inner" @_start @_end)) @block.outer + _+ @block.inner + "}") @block.outer ; classes (struct_declaration - . - (identifier) - . - (tag)* - . "{" - . - (_) @_first @_last - (_)? - "," @_last - . - "}" - (#make-range! "class.inner" @_first @_last)) @class.outer + _+ @class.inner + "}") @class.outer (union_declaration - . - (identifier) - . - (tag)* - . "{" - . - (_) @_first @_last - (_)? - "," @_last - . - "}" - (#make-range! "class.inner" @_first @_last)) @class.outer + _+ @class.inner + "}") @class.outer (enum_declaration - . - (identifier) - . - (tag)* - . "{" - . - (_) @_first @_last - (_)? - "," @_last - . - "}" - (#make-range! "class.inner" @_first @_last)) @class.outer + _+ @class.inner + "}") @class.outer ; comments (comment) @comment.outer @@ -96,13 +52,12 @@ ; assignment ; works also for multiple targets in lhs. ex. 'res, ok := get_res()' -((assignment_statement +(assignment_statement . - (_) @_first - (_) @_prelast + (_) @assignment.lhs + (_) @assignment.lhs . - (_) @assignment.rhs @assignment.inner .) - (#make-range! "assignment.lhs" @_first @_prelast)) @assignment.outer + (_) @assignment.rhs @assignment.inner .) @assignment.outer ; attribute (attribute @@ -112,30 +67,26 @@ (number) @number.inner ; parameters -((parameters - "," @_start +(parameters + "," @parameter.outer . - (parameter) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (parameter) @parameter.inner @parameter.outer) -((parameters +(parameters . - (parameter) @parameter.inner + (parameter) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((call_expression +(call_expression function: (_) - "," @_start + "," @parameter.outer . - argument: (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + argument: (_) @parameter.inner @parameter.outer) -((call_expression +(call_expression function: (_) . - argument: (_) @parameter.inner + argument: (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) diff --git a/queries/php/textobjects.scm b/queries/php/textobjects.scm index 09bdbd59..d7cd658e 100644 --- a/queries/php/textobjects.scm +++ b/queries/php/textobjects.scm @@ -3,12 +3,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (function_definition) @function.outer @@ -16,12 +12,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (anonymous_function) @function.outer @@ -30,12 +22,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (method_declaration) @function.outer @@ -44,12 +32,8 @@ body: (declaration_list . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (trait_declaration) @class.outer @@ -58,12 +42,8 @@ body: (declaration_list . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (interface_declaration) @class.outer @@ -72,12 +52,8 @@ body: (enum_declaration_list . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (enum_declaration) @class.outer @@ -86,12 +62,8 @@ body: (declaration_list . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (class_declaration) @class.outer @@ -100,12 +72,8 @@ (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) + _+ @loop.inner + "}")) (for_statement) @loop.outer @@ -113,12 +81,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) + _+ @loop.inner + "}")) (foreach_statement) @loop.outer @@ -126,12 +90,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) + _+ @loop.inner + "}")) (while_statement) @loop.outer @@ -139,12 +99,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) + _+ @loop.inner + "}")) (do_statement) @loop.outer @@ -153,12 +109,8 @@ body: (switch_block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end))) + _+ @conditional.inner + "}")) (switch_statement) @conditional.outer @@ -166,12 +118,8 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end))) + _+ @conditional.inner + "}")) (if_statement) @conditional.outer @@ -179,23 +127,15 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end))) + _+ @conditional.inner + "}")) (else_if_clause body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end))) + _+ @conditional.inner + "}")) ; blocks (_ @@ -203,30 +143,26 @@ ; parameters (arguments - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (arguments . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (formal_parameters - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (formal_parameters . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; comments (comment) @comment.outer @@ -244,45 +180,29 @@ arguments: (arguments . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) (member_call_expression arguments: (arguments . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) (nullsafe_member_call_expression arguments: (arguments . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) (scoped_call_expression arguments: (arguments . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) ; statement [ diff --git a/queries/prisma/textobjects.scm b/queries/prisma/textobjects.scm new file mode 100644 index 00000000..a79016b4 --- /dev/null +++ b/queries/prisma/textobjects.scm @@ -0,0 +1,22 @@ +[ + (comment) + (developer_comment) +] @comment.outer + +[ + (statement_block) + (enum_block) +] @block.outer + +(enum_declaration) @class.outer + +(enum_block) @class.inner + +(enumeral) @parameter.inner @parameter.outer + +(model_declaration) @class.outer + +(model_declaration + (statement_block) @class.inner) + +(column_declaration) @parameter.inner @parameter.outer diff --git a/queries/python/textobjects.scm b/queries/python/textobjects.scm index 0650bc5e..99920d4b 100644 --- a/queries/python/textobjects.scm +++ b/queries/python/textobjects.scm @@ -27,12 +27,12 @@ ; leave space after comment marker if there is one ((comment) @comment.inner @comment.outer - (#offset! @comment.inner 0 2 0) + (#offset! @comment.inner 0 2 0 0) (#lua-match? @comment.outer "# .*")) ; else remove everything accept comment marker ((comment) @comment.inner @comment.outer - (#offset! @comment.inner 0 1 0)) + (#offset! @comment.inner 0 1 0 0)) (block (_) @statement.outer) @@ -46,19 +46,15 @@ arguments: (argument_list . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) (return_statement (_)? @return.inner) @return.outer ; Parameters -((parameters - "," @_start +(parameters + "," @parameter.outer . [ (identifier) @@ -68,10 +64,9 @@ (typed_default_parameter) (dictionary_splat_pattern) (list_splat_pattern) - ] @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + ] @parameter.inner @parameter.outer) -((parameters +(parameters . [ (identifier) @@ -81,13 +76,12 @@ (typed_default_parameter) (dictionary_splat_pattern) (list_splat_pattern) - ] @parameter.inner + ] @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((lambda_parameters - "," @_start +(lambda_parameters + "," @parameter.outer . [ (identifier) @@ -97,10 +91,9 @@ (typed_default_parameter) (dictionary_splat_pattern) (list_splat_pattern) - ] @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + ] @parameter.inner @parameter.outer) -((lambda_parameters +(lambda_parameters . [ (identifier) @@ -110,104 +103,89 @@ (typed_default_parameter) (dictionary_splat_pattern) (list_splat_pattern) - ] @parameter.inner + ] @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((tuple - "," @_start +(tuple + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((tuple +(tuple "(" . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((list - "," @_start +(list + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((list +(list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((dictionary +(dictionary . - (pair) @parameter.inner + (pair) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((dictionary - "," @_start +(dictionary + "," @parameter.outer . - (pair) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (pair) @parameter.inner @parameter.outer) -((argument_list +(argument_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((argument_list - "," @_start +(argument_list + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((subscript +(subscript "[" . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((subscript - "," @_start +(subscript + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((import_statement +(import_statement . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((import_statement - "," @_start +(import_statement + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((import_from_statement - "," @_start +(import_from_statement + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((import_from_statement +(import_from_statement "import" . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) [ (integer) diff --git a/queries/r/textobjects.scm b/queries/r/textobjects.scm index 4aa08907..c989cb0e 100644 --- a/queries/r/textobjects.scm +++ b/queries/r/textobjects.scm @@ -44,31 +44,27 @@ (_) @statement.outer) ; parameter -((parameters - (comma) @_start +(parameters + (comma) @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((parameters +(parameters . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - (comma)? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + (comma)? @parameter.outer) -((arguments - (comma)? @_start +(arguments + (comma)? @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((arguments +(arguments . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - (comma)? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + (comma)? @parameter.outer) ; number (float) @number.inner diff --git a/queries/rust/textobjects.scm b/queries/rust/textobjects.scm index 5d6a1550..69aa90e9 100644 --- a/queries/rust/textobjects.scm +++ b/queries/rust/textobjects.scm @@ -7,12 +7,8 @@ body: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) ; quantifies as class(es) (struct_item) @class.outer @@ -21,15 +17,8 @@ body: (field_declaration_list . "{" - . - (_) @_start - [ - (_) - "," - ]? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (enum_item) @class.outer @@ -37,15 +26,8 @@ body: (enum_variant_list . "{" - . - (_) @_start - [ - (_) - "," - ]? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (union_item) @class.outer @@ -53,15 +35,8 @@ body: (field_declaration_list . "{" - . - (_) @_start - [ - (_) - "," - ]? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (trait_item) @class.outer @@ -69,12 +44,8 @@ body: (declaration_list . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (impl_item) @class.outer @@ -82,12 +53,8 @@ body: (declaration_list . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (mod_item) @class.outer @@ -95,12 +62,8 @@ body: (declaration_list . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) ; conditionals (if_expression @@ -127,43 +90,22 @@ body: (block . "{" - . - (_) @_start - [ - (_) - "," - ]? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer (while_expression body: (block . "{" - . - (_) @_start - [ - (_) - "," - ]? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer (for_expression body: (block . "{" - . - (_) @_start - [ - (_) - "," - ]? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) @loop.outer + _+ @loop.inner + "}")) @loop.outer ; blocks (_ @@ -179,12 +121,8 @@ (token_tree . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) (call_expression) @call.outer @@ -192,12 +130,8 @@ arguments: (arguments . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) ; returns (return_expression @@ -213,206 +147,176 @@ (block_comment) @comment.outer ; parameter -((parameters - "," @_start +(parameters + "," @parameter.outer . - (self_parameter) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (self_parameter) @parameter.inner @parameter.outer) -((parameters +(parameters . - (self_parameter) @parameter.inner + (self_parameter) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((parameters - "," @_start +(parameters + "," @parameter.outer . - (parameter) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (parameter) @parameter.inner @parameter.outer) -((parameters +(parameters . - (parameter) @parameter.inner + (parameter) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((parameters - "," @_start +(parameters + "," @parameter.outer . - (type_identifier) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (type_identifier) @parameter.inner @parameter.outer) -((parameters +(parameters . - (type_identifier) @parameter.inner + (type_identifier) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((type_parameters - "," @_start +(type_parameters + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((type_parameters +(type_parameters . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((tuple_pattern - "," @_start +(tuple_pattern + "," @parameter.outer . - (identifier) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (identifier) @parameter.inner @parameter.outer) -((tuple_pattern +(tuple_pattern . - (identifier) @parameter.inner + (identifier) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((tuple_struct_pattern - "," @_start +(tuple_struct_pattern + "," @parameter.outer . - (identifier) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (identifier) @parameter.inner @parameter.outer) -((tuple_struct_pattern +(tuple_struct_pattern . - (identifier) @parameter.inner + (identifier) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (tuple_expression - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (tuple_expression . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((tuple_type - "," @_start +(tuple_type + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((tuple_type +(tuple_type . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (struct_item body: (field_declaration_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner))) + (_) @parameter.inner @parameter.outer)) (struct_item body: (field_declaration_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end))) + ","? @parameter.outer)) (struct_expression body: (field_initializer_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner))) + (_) @parameter.inner @parameter.outer)) (struct_expression body: (field_initializer_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end))) + ","? @parameter.outer)) -((closure_parameters - "," @_start +(closure_parameters + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((closure_parameters +(closure_parameters . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((arguments - "," @_start +(arguments + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((arguments +(arguments . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((type_arguments - "," @_start +(type_arguments + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((type_arguments +(type_arguments . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((token_tree - "," @_start +(token_tree + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((token_tree +(token_tree . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (scoped_use_list list: (use_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner))) + (_) @parameter.inner @parameter.outer)) (scoped_use_list list: (use_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end))) + ","? @parameter.outer)) [ (integer_literal) diff --git a/queries/supercollider/textobjects.scm b/queries/supercollider/textobjects.scm index 550be443..3a463573 100644 --- a/queries/supercollider/textobjects.scm +++ b/queries/supercollider/textobjects.scm @@ -29,34 +29,30 @@ (_) @function.inner) @function.outer ;parameters -((parameter_call_list - "," @_start +(parameter_call_list + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((parameter_call_list +(parameter_call_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -(((symbol)? +((symbol)? (identifier) - "," @_start + "," @parameter.outer . ((method_name) (function_call - (_))) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_))) @parameter.inner @parameter.outer) -(((symbol)? +((symbol)? (identifier) . ((method_name) (function_call - (_))) @parameter.inner + (_))) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) diff --git a/queries/swift/textobjects.scm b/queries/swift/textobjects.scm index d9d218e2..69ef5775 100644 --- a/queries/swift/textobjects.scm +++ b/queries/swift/textobjects.scm @@ -2,54 +2,34 @@ body: (class_body . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) @class.outer + _+ @class.inner + "}")) @class.outer (class_declaration body: (enum_class_body . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) @class.outer + _+ @class.inner + "}")) @class.outer (function_declaration body: (function_body . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) @function.outer + _+ @function.inner + "}")) @function.outer (lambda_literal ("{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) @function.outer + _+ @function.inner + "}")) @function.outer (call_suffix (value_arguments . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) @call.outer + _+ @call.inner + ")")) @call.outer (value_argument value: (_) @parameter.inner) @parameter.outer diff --git a/queries/tact/textobjects.scm b/queries/tact/textobjects.scm index 328af9a0..2f64f6c1 100644 --- a/queries/tact/textobjects.scm +++ b/queries/tact/textobjects.scm @@ -9,12 +9,8 @@ body: (function_body . "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "function.inner" @_start @_end)) + _+ @function.inner + "}")) ; init (init_function @@ -24,12 +20,8 @@ body: (function_body . "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "function.inner" @_start @_end)) + _+ @function.inner + "}")) ; bounced (bounced_function @@ -39,12 +31,8 @@ body: (function_body . "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "function.inner" @_start @_end)) + _+ @function.inner + "}")) ; receive (receive_function @@ -54,12 +42,8 @@ body: (function_body . "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "function.inner" @_start @_end)) + _+ @function.inner + "}")) ; external (external_function @@ -69,12 +53,8 @@ body: (function_body . "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "function.inner" @_start @_end)) + _+ @function.inner + "}")) ; contract/trait function (storage_function @@ -84,12 +64,8 @@ body: (function_body . "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "function.inner" @_start @_end)) + _+ @function.inner + "}")) ; class.inner & outer ; ------------------- @@ -99,12 +75,8 @@ body: (struct_body . "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner + "}")) (message) @class.outer @@ -112,12 +84,8 @@ body: (message_body . "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner + "}")) (contract) @class.outer @@ -125,12 +93,8 @@ body: (contract_body . "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner + "}")) (trait) @class.outer @@ -138,12 +102,8 @@ body: (trait_body . "{" - . - (_) @_start - (_)? @_end - . - "}") - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner + "}")) ; attribute.inner & outer ; ----------------------- @@ -178,12 +138,8 @@ body: (block_statement . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) + _+ @loop.inner + "}")) (repeat_statement) @loop.outer @@ -191,12 +147,8 @@ body: (block_statement . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) + _+ @loop.inner + "}")) (do_until_statement) @loop.outer @@ -204,12 +156,8 @@ body: (block_statement . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) + _+ @loop.inner + "}")) (foreach_statement) @loop.outer @@ -217,12 +165,8 @@ body: (block_statement . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))) + _+ @loop.inner + "}")) ; conditional.inner & outer ; ------------------------- @@ -232,24 +176,16 @@ consequence: (block_statement . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end))) + _+ @conditional.inner + "}")) (if_statement alternative: (else_clause (block_statement . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end)))) + _+ @conditional.inner + "}"))) ; block.inner & outer ; ------------------- @@ -264,12 +200,8 @@ arguments: (argument_list . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) (static_call_expression) @call.outer @@ -277,12 +209,8 @@ arguments: (argument_list . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) (instance_expression) @call.outer @@ -290,25 +218,16 @@ arguments: (instance_argument_list . "{" - . - (_) @_start - (_)? @_end - . - "}" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + "}")) -((initOf - name: (identifier) @_name +(initOf + name: (identifier) @call.outer arguments: (argument_list . "(" - . - (_) @_start - (_)? @_end - . - ")") @_args) - (#make-range! "call.outer" @_name @_args) - (#make-range! "call.inner" @_start @_end)) + _+ @call.inner + ")") @call.outer) ; return.inner & outer ; -------------------- @@ -323,48 +242,42 @@ ; ----------------------- ; second and following (parameter_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) ; first (parameter_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; second and following (argument_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) ; first (argument_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; second and following (instance_argument_list - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) ; first (instance_argument_list . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; single parameter (receive_function diff --git a/queries/toml/textobjects.scm b/queries/toml/textobjects.scm index a7f1a2ce..b258a24f 100644 --- a/queries/toml/textobjects.scm +++ b/queries/toml/textobjects.scm @@ -6,28 +6,24 @@ (table (pair) @parameter.inner @parameter.outer) -((inline_table - "," @_start +(inline_table + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((inline_table +(inline_table . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) -((array - "," @_start +(array + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((array +(array . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) diff --git a/queries/twig/textobjects.scm b/queries/twig/textobjects.scm index 67938362..61e8bb4b 100644 --- a/queries/twig/textobjects.scm +++ b/queries/twig/textobjects.scm @@ -6,27 +6,23 @@ ; @parameter (arguments - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (arguments . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (parameters - "," @_start + "," @parameter.outer . - (_) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) (parameters . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) diff --git a/queries/typescript/textobjects.scm b/queries/typescript/textobjects.scm index 3fb8ce21..da02222b 100644 --- a/queries/typescript/textobjects.scm +++ b/queries/typescript/textobjects.scm @@ -6,12 +6,8 @@ body: (interface_body . "{" - . - (_) @_start @_end - _? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (type_alias_declaration) @class.outer @@ -19,12 +15,8 @@ value: (object_type . "{" - . - (_) @_start @_end - _? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (enum_declaration) @class.outer @@ -32,9 +24,5 @@ body: (enum_body . "{" - . - (_) @_start @_end - _? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) diff --git a/queries/v/textobjects.scm b/queries/v/textobjects.scm index 2d2f8696..e7ed4e69 100644 --- a/queries/v/textobjects.scm +++ b/queries/v/textobjects.scm @@ -27,12 +27,8 @@ (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}") - (#make-range! "block.inner" @_start @_end)) @block.outer + _+ @block.inner + "}")) @block.outer ; call (call_expression) @call.outer @@ -41,34 +37,26 @@ arguments: (argument_list . "(" - . - (_) @_start - (_)? @_end - . - ")" - (#make-range! "call.inner" @_start @_end))) + _+ @call.inner + ")")) ; class: structs (struct_declaration ("{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "class.inner" @_start @_end))) + _+ @class.inner + "}")) (struct_declaration) @class.outer ; comment ; leave space after comment marker if there is one ((line_comment) @comment.inner @comment.outer - (#offset! @comment.inner 0 3 0) + (#offset! @comment.inner 0 3 0 0) (#lua-match? @comment.outer "// .*")) ; else remove everything accept comment marker ((line_comment) @comment.inner @comment.outer - (#offset! @comment.inner 0 2 0)) + (#offset! @comment.inner 0 2 0 0)) (block_comment) @comment.inner @comment.outer @@ -77,24 +65,16 @@ block: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end))?) @conditional.outer + _+ @conditional.inner + "}")?) @conditional.outer ; function (function_declaration body: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) (function_declaration) @function.outer @@ -103,12 +83,8 @@ body: (block . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "loop.inner" @_start @_end))?) @loop.outer + _+ @loop.inner + "}")?) @loop.outer [ (int_literal) @@ -117,17 +93,15 @@ ; parameter (parameter_list - "," @_start + "," @parameter.outer . - (parameter_declaration) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (parameter_declaration) @parameter.inner @parameter.outer) (parameter_list . - (parameter_declaration) @parameter.inner + (parameter_declaration) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; return (return_statement diff --git a/queries/vim/textobjects.scm b/queries/vim/textobjects.scm index 076f93a5..a14e7ba2 100644 --- a/queries/vim/textobjects.scm +++ b/queries/vim/textobjects.scm @@ -6,18 +6,16 @@ (parameters (identifier) @parameter.inner) -((parameters - "," @_start +(parameters + "," @parameter.outer . - (identifier) @_end) - (#make-range! "parameter.outer" @_start @_end)) + (identifier) @parameter.outer) -((parameters +(parameters . - (identifier) @_start + (identifier) @parameter.outer . - "," @_end) - (#make-range! "parameter.outer" @_start @_end)) + "," @parameter.outer) (if_statement (body) @conditional.inner) @conditional.outer diff --git a/queries/wgsl/textobjects.scm b/queries/wgsl/textobjects.scm index dd135b3c..f4e1540d 100644 --- a/queries/wgsl/textobjects.scm +++ b/queries/wgsl/textobjects.scm @@ -4,25 +4,19 @@ body: (compound_statement . "{" - . - (_) @_start @_end - (_)? @_end - . - "}" - (#make-range! "function.inner" @_start @_end))) + _+ @function.inner + "}")) -((parameter_list - "," @_start +(parameter_list + "," @parameter.outer . - (parameter) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (parameter) @parameter.inner @parameter.outer) -((parameter_list +(parameter_list . - (parameter) @parameter.inner + (parameter) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) (compound_statement) @block.outer @@ -36,14 +30,10 @@ (while_statement (_)? @loop.inner) @loop.outer -((struct_declaration +(struct_declaration "{" - . - _ @_start - _ @_end - . + _+ @class.inner "}") @class.outer - (#make-range! "class.inner" @_start @_end)) ; conditional (if_statement @@ -53,15 +43,13 @@ (if_statement condition: (_) @conditional.inner) -((argument_list_expression - "," @_start +(argument_list_expression + "," @parameter.outer . - (_) @parameter.inner) - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer) -((argument_list_expression +(argument_list_expression . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end) - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) diff --git a/queries/yaml/textobjects.scm b/queries/yaml/textobjects.scm index 601036a3..1df02fd5 100644 --- a/queries/yaml/textobjects.scm +++ b/queries/yaml/textobjects.scm @@ -12,12 +12,12 @@ ; comment ; leave space after comment marker if there is one ((comment) @comment.inner @comment.outer - (#offset! @comment.inner 0 2 0) + (#offset! @comment.inner 0 2 0 0) (#lua-match? @comment.outer "# .*")) ; else remove everything accept comment marker ((comment) @comment.inner @comment.outer - (#offset! @comment.inner 0 1 0)) + (#offset! @comment.inner 0 1 0 0)) ; number [ diff --git a/queries/zig/textobjects.scm b/queries/zig/textobjects.scm index ea45ca91..e02c4a9f 100644 --- a/queries/zig/textobjects.scm +++ b/queries/zig/textobjects.scm @@ -6,12 +6,8 @@ (struct_declaration "struct" "{" - . - _ @_start @_end - _? @_end - . - "}") - (#make-range! "class.inner" @_start @_end)) + _+ @class.inner + "}")) ; functions (function_declaration) @function.outer @@ -20,12 +16,8 @@ body: (block . "{" - . - _ @_start @_end - _? @_end - . - "}") - (#make-range! "function.inner" @_start @_end)) + _+ @function.inner + "}")) ; loops (for_statement) @loop.outer @@ -43,49 +35,41 @@ (block "{" - . - _ @_start @_end - _? @_end - . - "}" - (#make-range! "block.inner" @_start @_end)) + _+ @block.inner + "}") ; statements (statement) @statement.outer ; parameters (parameters - "," @_start + "," @parameter.outer . - (parameter) @parameter.inner - (#make-range! "parameter.outer" @_start @parameter.inner)) + (parameter) @parameter.inner @parameter.outer) (parameters . - (parameter) @parameter.inner + (parameter) @parameter.inner @parameter.outer . - ","? @_end - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer) ; arguments (call_expression function: (_) "(" - "," @_start + "," @parameter.outer . - (_) @parameter.inner - ")" - (#make-range! "parameter.outer" @_start @parameter.inner)) + (_) @parameter.inner @parameter.outer + ")") (call_expression function: (_) "(" . - (_) @parameter.inner + (_) @parameter.inner @parameter.outer . - ","? @_end - ")" - (#make-range! "parameter.outer" @parameter.inner @_end)) + ","? @parameter.outer + ")") ; comments (comment) @comment.outer @@ -108,12 +92,8 @@ (switch_expression "{" - . - _ @_start - _? @_end - . - "}" - (#make-range! "conditional.inner" @_start @_end)) + _+ @conditional.inner + "}") (while_statement condition: (_) @conditional.inner) @@ -123,9 +103,5 @@ (call_expression "(" - . - _ @_start - _? @_end - . - ")" - (#make-range! "call.inner" @_start @_end)) + _+ @call.inner + ")") diff --git a/scripts/check-queries.lua b/scripts/check-queries.lua deleted file mode 100755 index 253793b0..00000000 --- a/scripts/check-queries.lua +++ /dev/null @@ -1,61 +0,0 @@ --- Execute as `nvim --headless -c "luafile ./scripts/check-queries.lua"` - -local function extract_captures() - local lines = vim.fn.readfile "CONTRIBUTING.md" - local captures = {} - local current_query - - for _, line in ipairs(lines) do - if vim.startswith(line, "### ") then - current_query = vim.fn.tolower(line:sub(5)) - elseif vim.startswith(line, "@") and current_query then - if not captures[current_query] then - captures[current_query] = {} - end - - table.insert(captures[current_query], vim.split(line:sub(2), " ", true)[1]) - end - end - - return captures -end - -local function do_check() - local parsers = require("nvim-treesitter.parsers").available_parsers() - local query_types = { "textobjects" } - - local captures = extract_captures() - - for _, lang in pairs(parsers) do - for _, query_type in pairs(query_types) do - print("Checking " .. lang .. " " .. query_type) - -- get_query deprecated since nvim 0.9 - local get_query = vim.treesitter.query.get or vim.treesitter.query.get_query - local query = get_query(lang, query_type) - - if query then - for _, capture in ipairs(query.captures) do - if - not vim.startswith(capture, "_") -- We ignore things like _helper - and captures[query_type] - and not capture:find "^[A-Z]" - and not vim.tbl_contains(captures[query_type], capture) - then - error(string.format("Invalid capture @%s in %s for %s.", capture, query_type, lang)) - end - end - end - end - end -end - -local ok, err = pcall(do_check) -if ok then - print "Check successful!\n" - vim.cmd "q" -else - print "Check failed:" - print(err) - print "\n" - vim.cmd "cq" -end diff --git a/scripts/ci-install-ubuntu-latest.sh b/scripts/ci-install-ubuntu-latest.sh deleted file mode 100755 index d658ea41..00000000 --- a/scripts/ci-install-ubuntu-latest.sh +++ /dev/null @@ -1,6 +0,0 @@ -wget "https://github.com/neovim/neovim/releases/download/${NVIM_TAG}/nvim-linux64.tar.gz" -tar -zxf nvim-linux64.tar.gz -sudo ln -s "$(pwd)/nvim-linux64/bin/nvim" /usr/local/bin -rm -rf "$(pwd)/nvim-linux64/lib/nvim/parser" -mkdir -p ~/.local/share/nvim/site/pack/ci/opt -ln -s "$(pwd)" ~/.local/share/nvim/site/pack/ci/opt diff --git a/scripts/ci-install.sh b/scripts/ci-install.sh new file mode 100755 index 00000000..3d656f84 --- /dev/null +++ b/scripts/ci-install.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +set -e + +NVIM_TAG=${NVIM_TAG-nightly} + +os=$(uname -s) +if [[ $os == Linux ]]; then + wget "https://github.com/neovim/neovim/releases/download/${NVIM_TAG}/nvim-linux-x86_64.tar.gz" + tar -zxf nvim-linux-x86_64.tar.gz + sudo ln -s "$PWD"/nvim-linux-x86_64/bin/nvim /usr/local/bin + rm -rf "$PWD"/nvim-linu-x86_x64/lib/nvim/parser +elif [[ $os == Darwin ]]; then + RELEASE_NAME="nvim-macos-$(uname -m)" + curl -L "https://github.com/neovim/neovim/releases/download/${NVIM_TAG}/$RELEASE_NAME.tar.gz" | tar -xz + sudo ln -s "$PWD/$RELEASE_NAME/bin/nvim" /usr/local/bin + rm -rf "$PWD/$RELEASE_NAME/lib/nvim/parser" +else + curl -L "https://github.com/neovim/neovim/releases/download/${NVIM_TAG}/nvim-win64.zip" -o nvim-win64.zip + unzip nvim-win64 +fi diff --git a/scripts/install_parsers.lua b/scripts/install_parsers.lua new file mode 100755 index 00000000..ab39d432 --- /dev/null +++ b/scripts/install_parsers.lua @@ -0,0 +1,10 @@ +#!/usr/bin/env -S nvim -l +vim.opt.runtimepath:append(os.getenv('NVIM_TS')) +vim.opt.runtimepath:append('.') + +local parsers = {} +for i = 1, #_G.arg do + parsers[#parsers + 1] = _G.arg[i] ---@type string +end + +require('nvim-treesitter').install(parsers, { force = true }):wait(1800000) -- wait max. 30 minutes diff --git a/scripts/minimal_init.lua b/scripts/minimal_init.lua index 8043e672..fc904b20 100644 --- a/scripts/minimal_init.lua +++ b/scripts/minimal_init.lua @@ -1,226 +1,414 @@ -vim.cmd [[ -packadd nvim-treesitter -packadd nvim-treesitter-textobjects -packadd plenary.nvim -TSUpdate -]] +vim.opt.runtimepath:append(os.getenv('PLENARY')) +vim.opt.runtimepath:append('.') +vim.cmd.runtime({ 'plugin/query_predicates.lua', bang = true }) -require("nvim-treesitter.configs").setup { - -- A list of parser names, or "all" - ensure_installed = "python", +require('nvim-treesitter-textobjects').setup({ + select = { + lookahead = true, + include_surrounding_whitespace = false, + selection_modes = { + ['@function.outer'] = 'V', -- linewise + }, + }, + move = { + set_jumps = true, + }, +}) - -- Install parsers synchronously (only applied to `ensure_installed`) - sync_install = true, +local select = require('nvim-treesitter-textobjects.select') - -- Automatically install missing parsers when entering buffer - -- Recommendation: set to false if you don't have `tree-sitter` CLI installed locally - auto_install = true, +for _, mode in ipairs({ 'x', 'o' }) do + vim.keymap.set(mode, 'am', function() + select.select_textobject('@function.outer', 'textobjects') + end) + vim.keymap.set(mode, 'im', function() + select.select_textobject('@function.inner', 'textobjects') + end) + vim.keymap.set(mode, 'al', function() + select.select_textobject('@class.outer', 'textobjects') + end) + vim.keymap.set(mode, 'il', function() + select.select_textobject('@class.inner', 'textobjects') + end) + vim.keymap.set(mode, 'ab', function() + select.select_textobject('@block.outer', 'textobjects') + end) + vim.keymap.set(mode, 'ib', function() + select.select_textobject('@block.inner', 'textobjects') + end) + vim.keymap.set(mode, 'ad', function() + select.select_textobject('@conditional.outer', 'textobjects') + end) + vim.keymap.set(mode, 'id', function() + select.select_textobject('@conditional.inner', 'textobjects') + end) + vim.keymap.set(mode, 'ao', function() + select.select_textobject('@loop.outer', 'textobjects') + end) + vim.keymap.set(mode, 'io', function() + select.select_textobject('@loop.inner', 'textobjects') + end) + vim.keymap.set(mode, 'aa', function() + select.select_textobject('@parameter.outer', 'textobjects') + end) + vim.keymap.set(mode, 'ia', function() + select.select_textobject('@parameter.inner', 'textobjects') + end) + vim.keymap.set(mode, 'af', function() + select.select_textobject('@call.outer', 'textobjects') + end) + vim.keymap.set(mode, 'if', function() + select.select_textobject('@call.inner', 'textobjects') + end) + vim.keymap.set(mode, 'ac', function() + select.select_textobject('@comment.outer', 'textobjects') + end) + vim.keymap.set(mode, 'ar', function() + select.select_textobject('@frame.outer', 'textobjects') + end) + vim.keymap.set(mode, 'ir', function() + select.select_textobject('@frame.inner', 'textobjects') + end) + vim.keymap.set(mode, 'at', function() + select.select_textobject('@attribute.outer', 'textobjects') + end) + vim.keymap.set(mode, 'it', function() + select.select_textobject('@attribute.inner', 'textobjects') + end) + vim.keymap.set(mode, 'ae', function() + select.select_textobject('@scopename.inner', 'textobjects') + end) + vim.keymap.set(mode, 'ie', function() + select.select_textobject('@scopename.inner', 'textobjects') + end) + vim.keymap.set(mode, 'as', function() + select.select_textobject('@statement.outer', 'textobjects') + end) + vim.keymap.set(mode, 'is', function() + select.select_textobject('@statement.outer', 'textobjects') + end) +end - ---- If you need to change the installation directory of the parsers (see -> Advanced Setup) - -- Remember to run vim.opt.runtimepath:append("/some/path/to/store/parsers")! - -- parser_install_dir = "/some/path/to/store/parsers", +-- swap +local swap = require('nvim-treesitter-textobjects.swap') - highlight = { - -- `false` will disable the whole extension - enable = true, +vim.keymap.set('n', ')m', function() + swap.swap_next('@function.outer') +end) +vim.keymap.set('n', ')c', function() + swap.swap_next('@comment.outer') +end) +vim.keymap.set('n', ')a', function() + swap.swap_next('@parameter.inner') +end) +vim.keymap.set('n', ')b', function() + swap.swap_next('@block.outer') +end) +vim.keymap.set('n', ')C', function() + swap.swap_next('@class.outer') +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 = true, - }, +vim.keymap.set('n', '(m', function() + swap.swap_previous('@function.outer') +end) +vim.keymap.set('n', '(c', function() + swap.swap_previous('@comment.outer') +end) +vim.keymap.set('n', '(a', function() + swap.swap_previous('@parameter.inner') +end) +vim.keymap.set('n', '(b', function() + swap.swap_previous('@block.outer') +end) +vim.keymap.set('n', '(C', function() + swap.swap_previous('@class.outer') +end) - textobjects = { - select = { - enable = true, +-- move +local move = require('nvim-treesitter-textobjects.move') - -- Automatically jump forward to textobj, similar to targets.vim - lookahead = true, +vim.keymap.set({ 'n', 'x', 'o' }, ']m', function() + move.goto_next_start('@function.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']f', function() + move.goto_next_start('@call.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']d', function() + move.goto_next_start('@conditional.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']o', function() + move.goto_next_start('@loop.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']s', function() + move.goto_next_start('@statement.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']a', function() + move.goto_next_start('@parameter.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']c', function() + move.goto_next_start('@comment.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']b', function() + move.goto_next_start('@block.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']l', function() + move.goto_next_start('@class.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']r', function() + move.goto_next_start('@frame.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']t', function() + move.goto_next_start('@attribute.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']e', function() + move.goto_next_start('@scopename.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]m', function() + move.goto_next_start('@function.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]f', function() + move.goto_next_start('@call.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]d', function() + move.goto_next_start('@conditional.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]o', function() + move.goto_next_start('@loop.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]a', function() + move.goto_next_start('@parameter.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]b', function() + move.goto_next_start('@block.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]l', function() + move.goto_next_start('@class.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]r', function() + move.goto_next_start('@frame.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]t', function() + move.goto_next_start('@attribute.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]e', function() + move.goto_next_start('@scopename.inner') +end) - keymaps = { - -- You can use the capture groups defined in textobjects.scm - ["am"] = "@function.outer", - ["im"] = "@function.inner", - ["al"] = "@class.outer", - -- You can optionally set descriptions to the mappings (used in the desc parameter of - -- nvim_buf_set_keymap) which plugins like which-key display - ["il"] = { query = "@class.inner", desc = "Select inner part of a class region" }, - ["ab"] = "@block.outer", - ["ib"] = "@block.inner", - ["ad"] = "@conditional.outer", - ["id"] = "@conditional.inner", - ["ao"] = "@loop.outer", - ["io"] = "@loop.inner", - ["aa"] = "@parameter.outer", - ["ia"] = "@parameter.inner", - ["af"] = "@call.outer", - ["if"] = "@call.inner", - ["ac"] = "@comment.outer", - ["ar"] = "@frame.outer", - ["ir"] = "@frame.inner", - ["at"] = "@attribute.outer", - ["it"] = "@attribute.inner", - ["ae"] = "@scopename.inner", - ["ie"] = "@scopename.inner", - ["as"] = "@statement.outer", - ["is"] = "@statement.outer", - }, - selection_modes = { - ["@function.outer"] = "V", -- linewise - }, - -- You can choose the select mode (default is charwise 'v') - -- - -- Can also be a function which gets passed a table with the keys - -- * query_string: eg '@function.inner' - -- * method: eg 'v' or 'o' - -- and should return the mode ('v', 'V', or '') or a table - -- mapping query_strings to modes. - -- selection_modes = treesitter_selection_mode, - -- if you set this to `true` (default is `false`) then any textobject is - -- extended to include preceding or succeeding whitespace. succeeding - -- whitespace has priority in order to act similarly to eg the built-in - -- `ap`. - -- - -- can also be a function which gets passed a table with the keys - -- * query_string: eg '@function.inner' - -- * selection_mode: eg 'v' - -- and should return true of false - include_surrounding_whitespace = false, - }, - swap = { - enable = true, - swap_next = { - [")m"] = "@function.outer", - [")c"] = "@comment.outer", - [")a"] = "@parameter.inner", - [")b"] = "@block.outer", - [")C"] = "@class.outer", - }, - swap_previous = { - ["(m"] = "@function.outer", - ["(c"] = "@comment.outer", - ["(a"] = "@parameter.inner", - ["(b"] = "@block.outer", - ["(C"] = "@class.outer", - }, - }, - move = { - enable = true, - set_jumps = true, -- whether to set jumps in the jumplist - goto_next_start = { - ["]m"] = "@function.outer", - ["]f"] = "@call.outer", - ["]d"] = "@conditional.outer", - ["]o"] = "@loop.outer", - ["]s"] = "@statement.outer", - ["]a"] = "@parameter.outer", - ["]c"] = "@comment.outer", - ["]b"] = "@block.outer", - ["]l"] = { query = "@class.outer", desc = "next class start" }, - ["]r"] = "@frame.outer", - ["]t"] = "@attribute.outer", - ["]e"] = "@scopename.outer", - ["]]m"] = "@function.inner", - ["]]f"] = "@call.inner", - ["]]d"] = "@conditional.inner", - ["]]o"] = "@loop.inner", - ["]]a"] = "@parameter.inner", - ["]]b"] = "@block.inner", - ["]]l"] = { query = "@class.inner", desc = "next class start" }, - ["]]r"] = "@frame.inner", - ["]]t"] = "@attribute.inner", - ["]]e"] = "@scopename.inner", - }, - goto_next_end = { - ["]M"] = "@function.outer", - ["]F"] = "@call.outer", - ["]D"] = "@conditional.outer", - ["]O"] = "@loop.outer", - ["]S"] = "@statement.outer", - ["]A"] = "@parameter.outer", - ["]C"] = "@comment.outer", - ["]B"] = "@block.outer", - ["]L"] = "@class.outer", - ["]R"] = "@frame.outer", - ["]T"] = "@attribute.outer", - ["]E"] = "@scopename.outer", - ["]]M"] = "@function.inner", - ["]]F"] = "@call.inner", - ["]]D"] = "@conditional.inner", - ["]]O"] = "@loop.inner", - ["]]A"] = "@parameter.inner", - ["]]B"] = "@block.inner", - ["]]L"] = "@class.inner", - ["]]R"] = "@frame.inner", - ["]]T"] = "@attribute.inner", - ["]]E"] = "@scopename.inner", - }, - goto_previous_start = { - ["[m"] = "@function.outer", - ["[f"] = "@call.outer", - ["[d"] = "@conditional.outer", - ["[o"] = "@loop.outer", - ["[s"] = "@statement.outer", - ["[a"] = "@parameter.outer", - ["[c"] = "@comment.outer", - ["[b"] = "@block.outer", - ["[l"] = "@class.outer", - ["[r"] = "@frame.outer", - ["[t"] = "@attribute.outer", - ["[e"] = "@scopename.outer", - ["[[m"] = "@function.inner", - ["[[f"] = "@call.inner", - ["[[d"] = "@conditional.inner", - ["[[o"] = "@loop.inner", - ["[[a"] = "@parameter.inner", - ["[[b"] = "@block.inner", - ["[[l"] = "@class.inner", - ["[[r"] = "@frame.inner", - ["[[t"] = "@attribute.inner", - ["[[e"] = "@scopename.inner", - }, - goto_previous_end = { - ["[M"] = "@function.outer", - ["[F"] = "@call.outer", - ["[D"] = "@conditional.outer", - ["[O"] = "@loop.outer", - ["[S"] = "@statement.outer", - ["[A"] = "@parameter.outer", - ["[C"] = "@comment.outer", - ["[B"] = "@block.outer", - ["[L"] = "@class.outer", - ["[R"] = "@frame.outer", - ["[T"] = "@attribute.outer", - ["[E"] = "@scopename.outer", - ["[[M"] = "@function.inner", - ["[[F"] = "@call.inner", - ["[[D"] = "@conditional.inner", - ["[[O"] = "@loop.inner", - ["[[A"] = "@parameter.inner", - ["[[B"] = "@block.inner", - ["[[L"] = "@class.inner", - ["[[R"] = "@frame.inner", - ["[[T"] = "@attribute.inner", - ["[[E"] = "@scopename.inner", - }, - }, - }, -} +vim.keymap.set({ 'n', 'x', 'o' }, ']M', function() + move.goto_next_end('@function.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']F', function() + move.goto_next_end('@call.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']D', function() + move.goto_next_end('@conditional.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']O', function() + move.goto_next_end('@loop.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']S', function() + move.goto_next_end('@statement.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']A', function() + move.goto_next_end('@parameter.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']C', function() + move.goto_next_end('@comment.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']B', function() + move.goto_next_end('@block.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']L', function() + move.goto_next_end('@class.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']R', function() + move.goto_next_end('@frame.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']T', function() + move.goto_next_end('@attribute.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']E', function() + move.goto_next_end('@scopename.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]M', function() + move.goto_next_end('@function.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]F', function() + move.goto_next_end('@call.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]D', function() + move.goto_next_end('@conditional.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]O', function() + move.goto_next_end('@loop.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]A', function() + move.goto_next_end('@parameter.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]B', function() + move.goto_next_end('@block.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]L', function() + move.goto_next_end('@class.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]R', function() + move.goto_next_end('@frame.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]T', function() + move.goto_next_end('@attribute.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, ']]E', function() + move.goto_next_end('@scopename.inner') +end) + +vim.keymap.set({ 'n', 'x', 'o' }, '[m', function() + move.goto_previous_start('@function.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[f', function() + move.goto_previous_start('@call.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[d', function() + move.goto_previous_start('@conditional.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[o', function() + move.goto_previous_start('@loop.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[s', function() + move.goto_previous_start('@statement.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[a', function() + move.goto_previous_start('@parameter.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[c', function() + move.goto_previous_start('@comment.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[b', function() + move.goto_previous_start('@block.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[l', function() + move.goto_previous_start('@class.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[r', function() + move.goto_previous_start('@frame.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[t', function() + move.goto_previous_start('@attribute.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[e', function() + move.goto_previous_start('@scopename.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[m', function() + move.goto_previous_start('@function.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[f', function() + move.goto_previous_start('@call.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[d', function() + move.goto_previous_start('@conditional.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[o', function() + move.goto_previous_start('@loop.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[a', function() + move.goto_previous_start('@parameter.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[b', function() + move.goto_previous_start('@block.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[l', function() + move.goto_previous_start('@class.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[r', function() + move.goto_previous_start('@frame.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[t', function() + move.goto_previous_start('@attribute.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[e', function() + move.goto_previous_start('@scopename.inner') +end) + +vim.keymap.set({ 'n', 'x', 'o' }, '[M', function() + move.goto_previous_end('@function.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[F', function() + move.goto_previous_end('@call.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[D', function() + move.goto_previous_end('@conditional.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[O', function() + move.goto_previous_end('@loop.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[S', function() + move.goto_previous_end('@statement.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[A', function() + move.goto_previous_end('@parameter.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[C', function() + move.goto_previous_end('@comment.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[B', function() + move.goto_previous_end('@block.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[L', function() + move.goto_previous_end('@class.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[R', function() + move.goto_previous_end('@frame.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[T', function() + move.goto_previous_end('@attribute.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[E', function() + move.goto_previous_end('@scopename.outer') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[M', function() + move.goto_previous_end('@function.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[F', function() + move.goto_previous_end('@call.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[D', function() + move.goto_previous_end('@conditional.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[O', function() + move.goto_previous_end('@loop.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[A', function() + move.goto_previous_end('@parameter.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[B', function() + move.goto_previous_end('@block.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[L', function() + move.goto_previous_end('@class.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[R', function() + move.goto_previous_end('@frame.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[T', function() + move.goto_previous_end('@attribute.inner') +end) +vim.keymap.set({ 'n', 'x', 'o' }, '[[E', function() + move.goto_previous_end('@scopename.inner') +end) -local ts_repeat_move = require "nvim-treesitter.textobjects.repeatable_move" +-- repeat +local ts_repeat_move = require('nvim-treesitter-textobjects.repeatable_move') -- Repeat movement with ; and , -- ensure ; goes forward and , goes backward regardless of the last direction --- vim.keymap.set({ "n", "x", "o" }, ";", ts_repeat_move.repeat_last_move_next) --- vim.keymap.set({ "n", "x", "o" }, ",", ts_repeat_move.repeat_last_move_previous) +vim.keymap.set({ 'n', 'x', 'o' }, ';', ts_repeat_move.repeat_last_move_next) +vim.keymap.set({ 'n', 'x', 'o' }, ',', ts_repeat_move.repeat_last_move_previous) -- vim way: ; goes to the direction you were moving. -vim.keymap.set({ "n", "x", "o" }, ";", ts_repeat_move.repeat_last_move) -vim.keymap.set({ "n", "x", "o" }, ",", ts_repeat_move.repeat_last_move_opposite) +-- vim.keymap.set({ 'n', 'x', 'o' }, ';', ts_repeat_move.repeat_last_move) +-- vim.keymap.set({ 'n', 'x', 'o' }, ',', ts_repeat_move.repeat_last_move_opposite) -- Optionally, make builtin f, F, t, T also repeatable with ; and , -vim.keymap.set({ "n", "x", "o" }, "f", ts_repeat_move.builtin_f_expr, { expr = true }) -vim.keymap.set({ "n", "x", "o" }, "F", ts_repeat_move.builtin_F_expr, { expr = true }) -vim.keymap.set({ "n", "x", "o" }, "t", ts_repeat_move.builtin_t_expr, { expr = true }) -vim.keymap.set({ "n", "x", "o" }, "T", ts_repeat_move.builtin_T_expr, { expr = true }) +vim.keymap.set({ 'n', 'x', 'o' }, 'f', ts_repeat_move.builtin_f_expr, { expr = true }) +vim.keymap.set({ 'n', 'x', 'o' }, 'F', ts_repeat_move.builtin_F_expr, { expr = true }) +vim.keymap.set({ 'n', 'x', 'o' }, 't', ts_repeat_move.builtin_t_expr, { expr = true }) +vim.keymap.set({ 'n', 'x', 'o' }, 'T', ts_repeat_move.builtin_T_expr, { expr = true }) diff --git a/scripts/pre-push b/scripts/pre-push deleted file mode 100755 index 00d4c507..00000000 --- a/scripts/pre-push +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -# Can be used as a pre-push hook -# Just symlink this file to .git/hooks/pre-push - -echo "Running style check..." -./scripts/style-check.sh diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh deleted file mode 100755 index c6660a7f..00000000 --- a/scripts/run_tests.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -HERE="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" -cd $HERE/.. - -run() { - nvim --headless --noplugin -u scripts/minimal_init.lua \ - -c "PlenaryBustedDirectory $1 { minimal_init = './scripts/minimal_init.lua' }" -} - -if [[ $2 = '--summary' ]]; then - ## really simple results summary by filtering plenary busted output - run tests/$1 2> /dev/null | grep -E '^\S*(Testing|Success|Failed|Errors)\s*:' -else - run tests/$1 -fi diff --git a/scripts/style-check.sh b/scripts/style-check.sh deleted file mode 100755 index 181ab458..00000000 --- a/scripts/style-check.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -luacheck `find -name "*.lua"` --codes diff --git a/scripts/update-readme.lua b/scripts/update-readme.lua index 328ed22c..2e83c888 100755 --- a/scripts/update-readme.lua +++ b/scripts/update-readme.lua @@ -1,6 +1,9 @@ -- Execute as `nvim --headless -c "luafile ./scripts/update-readme.lua"` -local parsers = require("nvim-treesitter.parsers").get_parser_configs() -local shared = require "nvim-treesitter.textobjects.shared" +vim.opt.runtimepath:append(os.getenv('NVIM_TS')) +vim.opt.runtimepath:append('.') + +local parsers = require('nvim-treesitter.parsers') +local shared = require('nvim-treesitter-textobjects.shared') local sorted_parsers = {} for k, v in pairs(parsers) do @@ -12,23 +15,23 @@ table.sort(sorted_parsers, function(a, b) end) local textobjects = {} -for m in table.concat(vim.fn.readfile "CONTRIBUTING.md", "\n"):gmatch "@[%w.]*" do +for m in table.concat(vim.fn.readfile('CONTRIBUTING.md'), '\n'):gmatch('@[%w.]*') do table.insert(textobjects, m) end table.sort(textobjects) -local generated_text = "" +local generated_text = '' for i, o in ipairs(textobjects) do - generated_text = generated_text .. i .. ". " .. o .. "\n" + generated_text = generated_text .. i .. '. ' .. o .. '\n' end -generated_text = generated_text .. "\n" +generated_text = generated_text .. '
\n' -generated_text = generated_text .. " " + generated_text = generated_text .. ' ' end -generated_text = generated_text .. "\n" +generated_text = generated_text .. '\n' for _, v in ipairs(sorted_parsers) do local lang = (v.parser.readme_name or v.name) @@ -44,36 +47,37 @@ for _, v in ipairs(sorted_parsers) do end if not none_found then - generated_text = generated_text .. "\n" - generated_text = generated_text .. "" + generated_text = generated_text .. '\n' + generated_text = generated_text .. '' for _, o in ipairs(textobjects) do local found = vim.tbl_contains(found_textobjects, o:sub(2)) - local status = found and "🟩" or "⬜" - generated_text = generated_text .. " " + local status = found and '🟩' or '⬜' + generated_text = generated_text + .. ' ' end - generated_text = generated_text .. "\n" + generated_text = generated_text .. '\n' end end -generated_text = generated_text .. "
\n" +generated_text = generated_text .. '\n' for i, _ in ipairs(textobjects) do - generated_text = generated_text .. "" .. i .. "' .. i .. '
" .. lang .. "
' .. lang .. '" .. '' .. status .. "" .. "' + .. '' + .. status + .. '' + .. '
\n" - -print(generated_text) -print "\n" +generated_text = generated_text .. '\n' -local readme_text = table.concat(vim.fn.readfile "README.md", "\n") +local readme_text = table.concat(vim.fn.readfile('README.md'), '\n') local new_readme_text = string.gsub( readme_text, - ".*", - "\n" .. generated_text .. "" + '.*', + '\n' .. generated_text .. '' ) -vim.fn.writefile(vim.fn.split(new_readme_text, "\n"), "README.md") +vim.fn.writefile(vim.fn.split(new_readme_text, '\n'), 'README.md') -if string.find(readme_text, generated_text, 1, "plain") then - print "README.md is up-to-date!" - vim.cmd "q" +if string.find(readme_text, generated_text, 1, true) then + print('README.md is up-to-date\n') else - print "New README.md was written. Please commit that change! Old text was: " - print(string.sub(readme_text, string.find(readme_text, ".*"))) - vim.cmd "cq" + print('New README.md was written\n') end diff --git a/tests/repeatable_move/common.lua b/tests/repeatable_move/common.lua index 2b098f38..2d825ed8 100644 --- a/tests/repeatable_move/common.lua +++ b/tests/repeatable_move/common.lua @@ -1,7 +1,7 @@ local M = {} -local assert = require "luassert" -local Path = require "plenary.path" +local assert = require('luassert') +local Path = require('plenary.path') -- Test in all possible col position -- f, F, t, T @@ -11,52 +11,52 @@ function M.run_builtin_find_test(file, spec) assert.are.same(1, vim.fn.filereadable(file), string.format('File "%s" not readable', file)) -- load reference file - vim.cmd(string.format("edit %s", file)) + vim.cmd(string.format('edit %s', file)) vim.api.nvim_win_set_cursor(0, { spec.row, 0 }) local line = vim.api.nvim_get_current_line() local num_cols = #line for col = 0, num_cols - 1 do - for _, cmd in pairs { "f", "F", "t", "T" } do - for _, repeat_cmd in pairs { ";", "," } do + for _, cmd in pairs({ 'f', 'F', 't', 'T' }) do + for _, repeat_cmd in pairs({ ';', ',' }) do -- Get ground truth using vim's built-in search and repeat vim.api.nvim_win_set_cursor(0, { spec.row, col }) local gt_cols = {} vim.cmd([[normal! ]] .. cmd .. spec.char) - gt_cols[#gt_cols + 1] = vim.fn.col "." + gt_cols[#gt_cols + 1] = vim.fn.col('.') vim.cmd([[normal! ]] .. repeat_cmd) - gt_cols[#gt_cols + 1] = vim.fn.col "." + gt_cols[#gt_cols + 1] = vim.fn.col('.') vim.cmd([[normal! 2]] .. repeat_cmd) - gt_cols[#gt_cols + 1] = vim.fn.col "." + gt_cols[#gt_cols + 1] = vim.fn.col('.') vim.cmd([[normal! l]] .. repeat_cmd) - gt_cols[#gt_cols + 1] = vim.fn.col "." + gt_cols[#gt_cols + 1] = vim.fn.col('.') vim.cmd([[normal! h]] .. repeat_cmd) - gt_cols[#gt_cols + 1] = vim.fn.col "." + gt_cols[#gt_cols + 1] = vim.fn.col('.') vim.cmd([[normal! 2]] .. cmd .. spec.char) - gt_cols[#gt_cols + 1] = vim.fn.col "." + gt_cols[#gt_cols + 1] = vim.fn.col('.') -- test using tstextobj repeatable_move.lua vim.api.nvim_win_set_cursor(0, { spec.row, col }) local ts_cols = {} vim.cmd([[normal ]] .. cmd .. spec.char) - assert.are.same(spec.row, vim.fn.line ".", "Command shouldn't move cursor over rows") - ts_cols[#ts_cols + 1] = vim.fn.col "." + assert.are.same(spec.row, vim.fn.line('.'), "Command shouldn't move cursor over rows") + ts_cols[#ts_cols + 1] = vim.fn.col('.') vim.cmd([[normal ]] .. repeat_cmd) - assert.are.same(spec.row, vim.fn.line ".", "Command shouldn't move cursor over rows") - ts_cols[#ts_cols + 1] = vim.fn.col "." + assert.are.same(spec.row, vim.fn.line('.'), "Command shouldn't move cursor over rows") + ts_cols[#ts_cols + 1] = vim.fn.col('.') vim.cmd([[normal 2]] .. repeat_cmd) - assert.are.same(spec.row, vim.fn.line ".", "Command shouldn't move cursor over rows") - ts_cols[#ts_cols + 1] = vim.fn.col "." + assert.are.same(spec.row, vim.fn.line('.'), "Command shouldn't move cursor over rows") + ts_cols[#ts_cols + 1] = vim.fn.col('.') vim.cmd([[normal l]] .. repeat_cmd) - assert.are.same(spec.row, vim.fn.line ".", "Command shouldn't move cursor over rows") - ts_cols[#ts_cols + 1] = vim.fn.col "." + assert.are.same(spec.row, vim.fn.line('.'), "Command shouldn't move cursor over rows") + ts_cols[#ts_cols + 1] = vim.fn.col('.') vim.cmd([[normal h]] .. repeat_cmd) - assert.are.same(spec.row, vim.fn.line ".", "Command shouldn't move cursor over rows") - ts_cols[#ts_cols + 1] = vim.fn.col "." + assert.are.same(spec.row, vim.fn.line('.'), "Command shouldn't move cursor over rows") + ts_cols[#ts_cols + 1] = vim.fn.col('.') vim.cmd([[normal 2]] .. cmd .. spec.char) - assert.are.same(spec.row, vim.fn.line ".", "Command shouldn't move cursor over rows") - ts_cols[#ts_cols + 1] = vim.fn.col "." + assert.are.same(spec.row, vim.fn.line('.'), "Command shouldn't move cursor over rows") + ts_cols[#ts_cols + 1] = vim.fn.col('.') assert.are.same( gt_cols, @@ -67,7 +67,7 @@ function M.run_builtin_find_test(file, spec) end end -- clear any changes to avoid 'No write since last change (add ! to override)' - vim.cmd "edit!" + vim.cmd('edit!') end local Runner = {} @@ -87,7 +87,7 @@ end function Runner:builtin_find(file, spec, title) title = title and title or tostring(spec.row) - self.it(string.format("%s[%s]", file, title), function() + self.it(string.format('%s[%s]', file, title), function() local path = self.base_dir / file M.run_builtin_find_test(path.filename, spec) end) diff --git a/tests/repeatable_move/python_spec.lua b/tests/repeatable_move/python_spec.lua index a5069258..3437c4f4 100644 --- a/tests/repeatable_move/python_spec.lua +++ b/tests/repeatable_move/python_spec.lua @@ -1,14 +1,14 @@ -local Runner = require("tests.repeatable_move.common").Runner +local Runner = require('tests.repeatable_move.common').Runner -local run = Runner:new(it, "tests/repeatable_move/python", { +local run = Runner:new(it, 'tests/repeatable_move/python', { tabstop = 4, shiftwidth = 4, softtabstop = 0, expandtab = true, }) -describe("builtin find Python:", function() - describe("repeat:", function() - run:builtin_find("aligned_indent.py", { row = 1, char = "n" }) +describe('builtin find Python:', function() + describe('repeat:', function() + run:builtin_find('aligned_indent.py', { row = 1, char = 'n' }) end) end) diff --git a/tests/select/common.lua b/tests/select/common.lua index 25718a25..b5d29c7b 100644 --- a/tests/select/common.lua +++ b/tests/select/common.lua @@ -1,13 +1,13 @@ local M = {} -local assert = require "luassert" -local Path = require "plenary.path" +local assert = require('luassert') +local Path = require('plenary.path') function M.run_compare_cmds_test(file, spec, equal) assert.are.same(1, vim.fn.filereadable(file), string.format('File "%s" not readable', file)) -- load reference file - vim.cmd(string.format("edit %s", file)) + vim.cmd(string.format('edit %s', file)) local to_compare_to = nil for _, cmd in pairs(spec.cmds) do @@ -20,17 +20,17 @@ function M.run_compare_cmds_test(file, spec, equal) -- clear any changes (avoid no write since last change) -- call before assert - vim.cmd "edit!" + vim.cmd('edit!') if to_compare_to == nil then to_compare_to = lines else local assert_statement = equal and assert.are.same or assert.are.Not.same - local message = equal and "different" or "same" + local message = equal and 'different' or 'same' assert_statement( to_compare_to, lines, - string.format("Commands %s and %s produces %s results", spec.cmds[1], cmd, message) + string.format('Commands %s and %s produces %s results', spec.cmds[1], cmd, message) ) end end @@ -52,8 +52,8 @@ function Runner:new(it, base_dir, buf_opts) end function Runner:compare_cmds(file, spec, title, equal) - title = title and title or string.format("%s,%s", spec.row, spec.col) - self.it(string.format("%s[%s]", file, title), function() + title = title and title or string.format('%s,%s', spec.row, spec.col) + self.it(string.format('%s[%s]', file, title), function() local path = self.base_dir / file M.run_compare_cmds_test(path.filename, spec, equal == nil and true or equal) end) diff --git a/tests/select/python_spec.lua b/tests/select/python_spec.lua index 5a32723a..9efd6c9c 100644 --- a/tests/select/python_spec.lua +++ b/tests/select/python_spec.lua @@ -1,28 +1,33 @@ -local Runner = require("tests.select.common").Runner +local Runner = require('tests.select.common').Runner -local run = Runner:new(it, "tests/select/python", { +local run = Runner:new(it, 'tests/select/python', { tabstop = 4, shiftwidth = 4, softtabstop = 0, expandtab = true, }) -describe("command equality Python:", function() - run:compare_cmds("aligned_indent.py", { row = 1, col = 0, cmds = { "daa", "vaad", "caa" } }) - run:compare_cmds("aligned_indent.py", { row = 1, col = 10, cmds = { "dia", "viad", "cia" } }) - run:compare_cmds("aligned_indent.py", { +describe('command equality Python:', function() + run:compare_cmds('aligned_indent.py', { row = 1, col = 0, cmds = { 'daa', 'vaad', 'caa' } }) + run:compare_cmds('aligned_indent.py', { row = 1, col = 10, cmds = { 'dia', 'viad', 'cia' } }) + run:compare_cmds('aligned_indent.py', { row = 1, col = 0, cmds = { - "diahx", - "viadhx", - "cia", + 'diahx', + 'viadhx', + 'cia', }, }) -- select using built-in finds (f, F, t, T) - run:compare_cmds("aligned_indent.py", { row = 1, col = 0, cmds = { "dfi", "vfid", "cfi" } }) + run:compare_cmds('aligned_indent.py', { row = 1, col = 0, cmds = { 'dfi', 'vfid', 'cfi' } }) + -- repeatable move should work like default behavior (#699) + run:compare_cmds('aligned_indent.py', { row = 1, col = 0, cmds = { 'dfn', 'd;' } }) -- select using move - run:compare_cmds("aligned_indent.py", { row = 1, col = 0, cmds = { "d]a", "v]ad", "c]a" } }) - run:compare_cmds("selection_mode.py", { row = 2, col = 4, cmds = { "dam", "dVam", "vamd", "Vamd" } }) - run:compare_cmds("selection_mode.py", { row = 5, col = 8, cmds = { "dVao", "dao" } }, nil, false) + run:compare_cmds('aligned_indent.py', { row = 1, col = 0, cmds = { 'd]a', 'v]ad', 'c]a' } }) + run:compare_cmds( + 'selection_mode.py', + { row = 2, col = 4, cmds = { 'dam', 'dVam', 'vamd', 'Vamd' } } + ) + run:compare_cmds('selection_mode.py', { row = 5, col = 8, cmds = { 'dVao', 'dao' } }, nil, false) end)