mirror of
https://github.com/chenasraf/vim-matchup.git
synced 2026-05-17 17:38:01 +00:00
Merge pull request #390 from TheLeoP/update-treesitter
Remove nvim-treesitter dependency
This commit is contained in:
8
.dockerignore
Normal file
8
.dockerignore
Normal file
@@ -0,0 +1,8 @@
|
||||
.github
|
||||
.gitignore
|
||||
.gitlab-ci-yml
|
||||
.luacheckrc
|
||||
.projections.json
|
||||
.vintrc
|
||||
*Dockerfile
|
||||
test/new/env
|
||||
46
.github/workflows/neovim.yml
vendored
46
.github/workflows/neovim.yml
vendored
@@ -3,7 +3,7 @@ name: Neovim
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
- "*"
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
@@ -13,28 +13,52 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
neovim_version:
|
||||
- 'head'
|
||||
- 'v0.10.1'
|
||||
- "head"
|
||||
- "v0.11.2"
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TESTS_ENABLE_TREESITTER: 1
|
||||
steps:
|
||||
- uses: 'actions/checkout@v2'
|
||||
- uses: "actions/checkout@v2"
|
||||
- uses: tree-sitter/setup-action@v2
|
||||
with:
|
||||
install-lib: false
|
||||
|
||||
- name: Install vader.vim
|
||||
run: git clone --depth=1 https://github.com/junegunn/vader.vim.git test/vader/vader.vim
|
||||
|
||||
- name: 'setup Neovim'
|
||||
uses: 'thinca/action-setup-vim@v2'
|
||||
- name: "setup Neovim"
|
||||
uses: "thinca/action-setup-vim@v2"
|
||||
with:
|
||||
vim_version: '${{ matrix.neovim_version }}'
|
||||
vim_type: 'Neovim'
|
||||
vim_version: "${{ matrix.neovim_version }}"
|
||||
vim_type: "Neovim"
|
||||
|
||||
- name: 'Show version'
|
||||
- name: "Show version"
|
||||
run: nvim --version
|
||||
|
||||
- name: 'Run test'
|
||||
- name: Clone tree-sitter-python
|
||||
run: git clone --depth=1 https://github.com/tree-sitter/tree-sitter-python.git
|
||||
working-directory: /tmp
|
||||
|
||||
- name: Clone tree-sitter-ruby
|
||||
run: git clone --depth=1 https://github.com/tree-sitter/tree-sitter-ruby.git
|
||||
working-directory: /tmp
|
||||
|
||||
- name: Create default nvim runtime parser directory
|
||||
run: mkdir -p $HOME/.local/share/nvim/site/parser
|
||||
|
||||
- name: Build tree-sitter-python
|
||||
run: tree-sitter build -o $HOME/.local/share/nvim/site/parser/python.so
|
||||
working-directory: /tmp/tree-sitter-python
|
||||
|
||||
- name: Build tree-sitter-ruby
|
||||
run: tree-sitter build -o $HOME/.local/share/nvim/site/parser/ruby.so
|
||||
working-directory: /tmp/tree-sitter-ruby
|
||||
|
||||
- name: "Run test"
|
||||
run: |
|
||||
bash -c 'VIMCMD=nvim test/vader/run'
|
||||
|
||||
- name: 'Run new tests'
|
||||
- name: "Run new tests"
|
||||
run: |
|
||||
cd ./test/new && make -j1 && make -j1 coverage
|
||||
|
||||
51
.github/workflows/neovim_treesitter.yml
vendored
51
.github/workflows/neovim_treesitter.yml
vendored
@@ -1,51 +0,0 @@
|
||||
name: Neovim with Tree-sitter
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
neovim_version:
|
||||
- 'head'
|
||||
- 'v0.10.1'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TESTS_ENABLE_TREESITTER: 1
|
||||
steps:
|
||||
- uses: 'actions/checkout@v2'
|
||||
|
||||
- name: Install vader.vim
|
||||
run: git clone --depth=1 https://github.com/junegunn/vader.vim.git test/vader/vader.vim
|
||||
|
||||
- name: 'setup Neovim'
|
||||
uses: 'thinca/action-setup-vim@v2'
|
||||
with:
|
||||
vim_version: '${{ matrix.neovim_version }}'
|
||||
vim_type: 'Neovim'
|
||||
|
||||
- name: Install nvim-treesitter
|
||||
run: git clone --depth=1 https://github.com/nvim-treesitter/nvim-treesitter.git test/vader/plugged/nvim-treesitter
|
||||
|
||||
- name: Install python treesitter module
|
||||
run: nvim --headless -Nu test/vader/minvimrc -c 'TSInstallSync python' -c 'q'
|
||||
|
||||
- name: 'Show version'
|
||||
run: nvim --version
|
||||
|
||||
- name: 'Run test'
|
||||
run: |
|
||||
bash -c 'VIMCMD=nvim test/vader/run'
|
||||
|
||||
- name: Install ruby treesitter module
|
||||
run: nvim --headless -Nu test/vader/minvimrc -c 'TSInstallSync ruby' -c 'q'
|
||||
|
||||
- name: 'Run new tests'
|
||||
run: |
|
||||
cd ./test/new && make -j1 && make -j1 coverage
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
doc/tags
|
||||
.nvim.lua
|
||||
|
||||
25
Makefile
Normal file
25
Makefile
Normal file
@@ -0,0 +1,25 @@
|
||||
PHONY: docker_build docker_test_nvim
|
||||
|
||||
RUNFOR ?= nvim
|
||||
VIMCMD = $(shell if [ $(RUNFOR) = nvim ]; then echo "nvim --headless"; else echo "vim -T dumb --not-a-term -n"; fi)
|
||||
VIMCMD != if [ $(RUNFOR) = nvim ]; then echo "nvim --headless"; else echo "vim -T dumb --not-a-term -n"; fi
|
||||
NVIM_VERSION ?= stable
|
||||
NVIM_ARCH ?= -linux-x86_64
|
||||
VIM_VERSION ?= v9.1.1287
|
||||
|
||||
docker_build:
|
||||
docker build --tag 'vim-matchup-nvim-stable' \
|
||||
--file vim.Dockerfile \
|
||||
--build-arg NVIM_VERSION=${NVIM_VERSION} \
|
||||
--build-arg NVIM_ARCH=${NVIM_ARCH} \
|
||||
--build-arg VIM_VERSION=${VIM_VERSION} \
|
||||
.
|
||||
|
||||
docker_test_old: docker_build
|
||||
docker run --rm -it --pull=never --name nvim vim-matchup-nvim-stable -c 'VIMCMD="${VIMCMD}" test/vader/run'
|
||||
|
||||
docker_test_new: docker_build
|
||||
docker run --rm -it --pull=never --name nvim vim-matchup-nvim-stable -c 'cd ./test/new && make -j1 MYVIM="${VIMCMD}"'
|
||||
|
||||
docker_test_shell: docker_build
|
||||
docker run --rm -it --pull=never --name nvim vim-matchup-nvim-stable
|
||||
367
README.md
367
README.md
@@ -9,7 +9,7 @@
|
||||
</h1>
|
||||
|
||||
match-up is a plugin that lets you highlight, navigate, and operate on
|
||||
sets of matching text. It extends vim's `%` key to language-specific
|
||||
sets of matching text. It extends vim's `%` key to language-specific
|
||||
words instead of just single characters.
|
||||
|
||||
## Screenshot
|
||||
@@ -18,20 +18,20 @@ words instead of just single characters.
|
||||
|
||||
## Table of contents
|
||||
|
||||
* [Overview](#overview)
|
||||
* [Installation](#installation)
|
||||
* [Features](#features)
|
||||
* [Options](#options)
|
||||
* [FAQ](#faq)
|
||||
* [Interoperability](#interoperability)
|
||||
* [Acknowledgments](#acknowledgments)
|
||||
* [Development](#development)
|
||||
- [Overview](#overview)
|
||||
- [Installation](#installation)
|
||||
- [Features](#features)
|
||||
- [Options](#options)
|
||||
- [FAQ](#faq)
|
||||
- [Interoperability](#interoperability)
|
||||
- [Acknowledgments](#acknowledgments)
|
||||
- [Development](#development)
|
||||
|
||||
## Overview
|
||||
|
||||
match-up can be used as a drop-in replacement for the classic plugin [matchit.vim].
|
||||
match-up aims to enhance all of matchit's features, fix a number of its
|
||||
deficiencies and bugs, and add a few totally new features. It also
|
||||
deficiencies and bugs, and add a few totally new features. It also
|
||||
replaces the standard plugin [matchparen], allowing all of matchit's words
|
||||
to be highlighted along with the `matchpairs` (`(){}[]`).
|
||||
|
||||
@@ -39,9 +39,9 @@ to be highlighted along with the `matchpairs` (`(){}[]`).
|
||||
[matchparen]: http://ftp.vim.org/pub/vim/runtime/doc/pi_paren.txt
|
||||
|
||||
See [detailed feature documentation](#detailed-feature-documentation) for
|
||||
more information. This plugin:
|
||||
more information. This plugin:
|
||||
|
||||
- Extends vim's `%` motion to language-specific words. The following vim
|
||||
- Extends vim's `%` motion to language-specific words. The following vim
|
||||
file type plugins currently provide special support for match-up:
|
||||
|
||||
> abaqus, ada, aspvbs, bash, c, cpp, chicken, clojure, cmake, cobol,
|
||||
@@ -60,7 +60,7 @@ more information. This plugin:
|
||||
- Adds motions `g%`, `[%`, `]%`, and `z%`.
|
||||
- Combines these motions into convenient text objects `i%` and `a%`.
|
||||
- Highlights symbols and words under the cursor which `%` can work on,
|
||||
and highlights matching symbols and words. Now you can easily tell
|
||||
and highlights matching symbols and words. Now you can easily tell
|
||||
where `%` will jump to.
|
||||
|
||||
## Installation
|
||||
@@ -91,28 +91,43 @@ end)
|
||||
|
||||
and run `:PackerSync` or similar.
|
||||
|
||||
See [Tree-sitter integration](https://github.com/andymass/vim-matchup#tree-sitter-integration)
|
||||
for information on how to enable tree-sitter matching with neovim.
|
||||
|
||||
Note: I do not recommend using alternative loading strategies such as
|
||||
`event = 'VimEnter'` or `event = 'CursorMoved'` as match-up already
|
||||
loads a minimal amount of code on start-up. It may work, but if you run
|
||||
into issues, remove the event key as a first debugging step.
|
||||
|
||||
With [LunarVim](https://www.lunarvim.org/), tree-sitter integration can be
|
||||
enabled as follows:
|
||||
If you use [lazy.nvim](https://github.com/folke/lazy.nvim), add the following
|
||||
to your plugins spec
|
||||
|
||||
```lua
|
||||
{
|
||||
"andymass/vim-matchup",
|
||||
setup = function()
|
||||
vim.g.matchup_matchparen_offscreen = { method = "popup" }
|
||||
end,
|
||||
},
|
||||
'andymass/vim-matchup'
|
||||
init = function()
|
||||
-- modify your configuration vars here
|
||||
vim.g.matchup_treesitter_stopline = 500
|
||||
|
||||
lvim.builtin.treesitter.matchup.enable = true
|
||||
-- or call the setup function provided as a helper. It defines the
|
||||
-- configuration vars for you
|
||||
require('match-up').setup({
|
||||
treesitter = {
|
||||
stopline = 500
|
||||
}
|
||||
})
|
||||
end,
|
||||
-- or use the `opts` mechanism built into `lazy.nvim`. It calls
|
||||
-- `require('match-up').setup` under the hood
|
||||
---@type matchup.Config
|
||||
opts = {
|
||||
treesitter = {
|
||||
stopline = 500,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See [Tree-sitter integration](https://github.com/andymass/vim-matchup#tree-sitter-integration)
|
||||
for information on how the tree-sitter integration works on Neovim.
|
||||
|
||||
Note: I do not recommend using alternative loading strategies such as
|
||||
`event = 'VimEnter'` or `event = 'CursorMoved'` as match-up already
|
||||
loads a minimal amount of code on start-up. It may work, but if you run
|
||||
into issues, remove the event key as a first debugging step.
|
||||
|
||||
You can use any other plugin manager such as
|
||||
[vundle](https://github.com/gmarik/vundle),
|
||||
[dein](https://github.com/Shougo/dein.vim),
|
||||
@@ -131,39 +146,18 @@ together with other plugins.
|
||||
|
||||
### Tree-sitter integration
|
||||
|
||||
_Note: Currently this feature is possible in neovim only. Only the latest
|
||||
version of neovim is supported._
|
||||
_Note: Currently this feature is possible in Neovim only. Only the latest
|
||||
stable version of Neovim is supported._
|
||||
|
||||
match-up has support for language syntax provided by tree-sitter. The
|
||||
match-up has support for language syntax provided by tree-sitter. The
|
||||
list of supported languages is available
|
||||
[here](https://github.com/andymass/vim-matchup/tree/master/after/queries).
|
||||
|
||||
This feature requires manual opt-in in your init.vim and requires
|
||||
[nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) to
|
||||
be installed.
|
||||
This feature is automatically enabled if you are using Neovim. And does not
|
||||
require other plugins to work.
|
||||
|
||||
```vim
|
||||
Plug 'nvim-treesitter/nvim-treesitter'
|
||||
lua <<EOF
|
||||
require'nvim-treesitter.configs'.setup {
|
||||
matchup = {
|
||||
enable = true, -- mandatory, false will disable the whole extension
|
||||
disable = { "c", "ruby" }, -- optional, list of language that will be disabled
|
||||
-- [options]
|
||||
},
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
Beside `enable` and `disable`, the following options are available, all
|
||||
defaulting to disabled:
|
||||
|
||||
- `disable_virtual_text`: do not use virtual text to highlight the
|
||||
virtual end of a block, for languages without explicit end markers
|
||||
(e.g., Python).
|
||||
- `include_match_words`: additionally include traditional vim regex
|
||||
matches for symbols. For example, highlights `/* */` comments in C++
|
||||
which are not supported in tree-sitter matching.
|
||||
The treesitter related configuration options share the prefix
|
||||
`g:matchup_treesitter`. You can check them on `:h g:matchup_treesitter_enabled`
|
||||
|
||||
Screenshot:
|
||||
|
||||
@@ -171,18 +165,18 @@ Screenshot:
|
||||
|
||||
## Features
|
||||
|
||||
| | feature | __match-up__ | matchit | matchparen |
|
||||
| ------- | -------------------------------- | -------------- | ------------- | ------------- |
|
||||
| ([a.1]) | jump between matching words | :thumbsup: | :thumbsup: | :x: |
|
||||
| ([a.2]) | jump to open & close words | :thumbsup: | :thumbsup: | :x: |
|
||||
| ([a.3]) | jump inside (`z%`) | :thumbsup: | :x: | :x: |
|
||||
| ([b.1]) | full set of text objects | :thumbsup: | :question: | :x: |
|
||||
| ([b.2]) | delete surrounding matched words | :thumbsup: | :x: | :x: |
|
||||
| ([c.1]) | highlight `()`, `[]`, & `{}` | :thumbsup: | :x: | :thumbsup: |
|
||||
| ([c.2]) | highlight _all_ matching words | :thumbsup: | :x: | :x: |
|
||||
| ([c.3]) | display matches off-screen | :thumbsup: | :x: | :x: |
|
||||
| ([c.4]) | show where you are (breadcrumbs) | :thumbsup: | :x: | :x: |
|
||||
| ([d.1]) | (neovim) tree-sitter integration | :thumbsup: | :x: | :x: |
|
||||
| | feature | **match-up** | matchit | matchparen |
|
||||
| ------- | -------------------------------- | ------------ | ---------- | ---------- |
|
||||
| ([a.1]) | jump between matching words | :thumbsup: | :thumbsup: | :x: |
|
||||
| ([a.2]) | jump to open & close words | :thumbsup: | :thumbsup: | :x: |
|
||||
| ([a.3]) | jump inside (`z%`) | :thumbsup: | :x: | :x: |
|
||||
| ([b.1]) | full set of text objects | :thumbsup: | :question: | :x: |
|
||||
| ([b.2]) | delete surrounding matched words | :thumbsup: | :x: | :x: |
|
||||
| ([c.1]) | highlight `()`, `[]`, & `{}` | :thumbsup: | :x: | :thumbsup: |
|
||||
| ([c.2]) | highlight _all_ matching words | :thumbsup: | :x: | :x: |
|
||||
| ([c.3]) | display matches off-screen | :thumbsup: | :x: | :x: |
|
||||
| ([c.4]) | show where you are (breadcrumbs) | :thumbsup: | :x: | :x: |
|
||||
| ([d.1]) | (Neovim) tree-sitter integration | :thumbsup: | :x: | :x: |
|
||||
|
||||
[a.1]: #a1-jump-between-matching-words
|
||||
[a.2]: #a2-jump-to-open-and-close-words
|
||||
@@ -198,12 +192,12 @@ Screenshot:
|
||||
[exclusive]: #inclusive-and-exclusive-motions
|
||||
|
||||
Legend: :thumbsup: supported.
|
||||
:question: poorly implemented, broken, or uncertain. :x: not possible.
|
||||
:question: poorly implemented, broken, or uncertain. :x: not possible.
|
||||
|
||||
### Detailed feature documentation
|
||||
|
||||
What do we mean by open, close, mid? This depends on the specific file
|
||||
type and is configured through the variable `b:match_words`. Here are a
|
||||
What do we mean by open, close, mid? This depends on the specific file
|
||||
type and is configured through the variable `b:match_words`. Here are a
|
||||
couple examples:
|
||||
|
||||
#### vim-script
|
||||
@@ -219,13 +213,14 @@ endif
|
||||
```
|
||||
|
||||
For the vim-script language, match-up understands the words `if`,
|
||||
`else`, `elseif`, `endif` and that they form a sequential construct. The
|
||||
`else`, `elseif`, `endif` and that they form a sequential construct. The
|
||||
"open" word is `if`, the "close" word is `endif`, and the "mid"
|
||||
words are `else` and `elseif`. The `if`/`endif` pair is called an
|
||||
words are `else` and `elseif`. The `if`/`endif` pair is called an
|
||||
"open-to-close" block and the `if`/`else`, `else`/`elsif`, and
|
||||
`elseif`/`endif` are called "any" blocks.
|
||||
|
||||
#### C, C++
|
||||
|
||||
```c
|
||||
#if 0
|
||||
#else
|
||||
@@ -246,57 +241,67 @@ Since in C and C++, blocks are delimited using braces (`{` & `}`),
|
||||
match-up will recognize `{` as the open word and `}` as the close word.
|
||||
It will ignore the `if` and `else if` because they are not defined in
|
||||
vim's default C file type plugin.
|
||||
(Note: In neovim, this is optionally supported via
|
||||
(Note: In Neovim, this is optionally supported via
|
||||
[Tree-sitter](#tree-sitter-integration))
|
||||
|
||||
On the other hand, match-up will recognize the `#if`, `#else`, `#endif`
|
||||
preprocessor directives.
|
||||
|
||||
#### (a.1) jump between matching words
|
||||
- `%` go forwards to next matching word. If at a close word,
|
||||
|
||||
- `%` go forwards to next matching word. If at a close word,
|
||||
cycle back to the corresponding open word.
|
||||
- `{count}%` forwards `{count}` times. Requires
|
||||
`{count} <= g:matchup_motion_override_Npercent`. For larger
|
||||
- `{count}%` forwards `{count}` times. Requires
|
||||
`{count} <= g:matchup_motion_override_Npercent`. For larger
|
||||
`{count}`, `{count}%` goes to the `{count}` percentage in the file.
|
||||
- `g%` go backwards to `[count]`th previous matching word. If at an
|
||||
- `g%` go backwards to `[count]`th previous matching word. If at an
|
||||
open word, cycle around to the corresponding close word.
|
||||
|
||||
#### (a.2) jump to open and close words
|
||||
- `[%` go to `[count]`th previous outer open word. Allows navigation
|
||||
to the start of blocks surrounding the cursor. This is similar to vim's
|
||||
built-in `[(` and `[{` and is an [exclusive] motion.
|
||||
- `]%` go to `[count]`th next surrounding close word. This is an
|
||||
[exclusive] motion.
|
||||
|
||||
- `[%` go to `[count]`th previous outer open word. Allows navigation
|
||||
to the start of blocks surrounding the cursor. This is similar to vim's
|
||||
built-in `[(` and `[{` and is an [exclusive] motion.
|
||||
- `]%` go to `[count]`th next surrounding close word. This is an
|
||||
[exclusive] motion.
|
||||
|
||||
#### (a.3) jump inside
|
||||
- `z%` go to inside `[count]`th nearest inner contained block. This
|
||||
|
||||
- `z%` go to inside `[count]`th nearest inner contained block. This
|
||||
is an [exclusive] motion when used with operators, except it eats
|
||||
whitespace. For example, where `█` is the cursor position,
|
||||
whitespace. For example, where `█` is the cursor position,
|
||||
|
||||
```vim
|
||||
█ call somefunction(param1, param2)
|
||||
```
|
||||
|
||||
`dz%` produces
|
||||
|
||||
```vim
|
||||
param1, param2)
|
||||
```
|
||||
|
||||
but in
|
||||
|
||||
```vim
|
||||
█ call somefunction( param1, param2)
|
||||
```
|
||||
|
||||
`dz%` also produces
|
||||
|
||||
```vim
|
||||
param1, param2)
|
||||
```
|
||||
|
||||
#### (b.1) full set of text objects
|
||||
|
||||
- `i%` the inside of an any block
|
||||
- `1i%` the inside of an open-to-close block
|
||||
- `{count}i%` If count is greater than 1, the inside of the `{count}`th
|
||||
surrounding open-to-close block
|
||||
|
||||
- `a%` an any block.
|
||||
- `1a%` an open-to-close block. Includes mids but does not include open
|
||||
- `1a%` an open-to-close block. Includes mids but does not include open
|
||||
and close words.
|
||||
- `{count}a%` if `{count}` is greater than 1, the `{count}`th surrounding
|
||||
open-to-close block.
|
||||
@@ -334,7 +339,7 @@ If both the open and close match are off-screen, the
|
||||
close match is preferred.
|
||||
See the option `g:matchup_matchparen_offscreen` for more details.
|
||||
|
||||
For popup style (supported in recent vim and neovim versions):
|
||||
For popup style (supported in recent vim and Neovim versions):
|
||||
|
||||
```vim
|
||||
let g:matchup_matchparen_offscreen = {'method': 'popup'}
|
||||
@@ -369,14 +374,14 @@ print out.
|
||||
### Inclusive and exclusive motions
|
||||
|
||||
In vim, character motions following operators (such as `d` for delete
|
||||
and `c` for change) are either [inclusive] or [exclusive]. This means
|
||||
they either include the ending position or not. Here, "ending position"
|
||||
and `c` for change) are either [inclusive] or [exclusive]. This means
|
||||
they either include the ending position or not. Here, "ending position"
|
||||
means the line and column closest to the end of the buffer of the region
|
||||
swept over by the motion. match-up is designed so that `d]%` inside a set
|
||||
swept over by the motion. match-up is designed so that `d]%` inside a set
|
||||
of parenthesis behaves exactly like `d])`, except generalized to words.
|
||||
|
||||
Put differently, _forward_ exclusive motions will not include the close
|
||||
word. In this example, where `█` is the cursor position,
|
||||
word. In this example, where `█` is the cursor position,
|
||||
|
||||
```vim
|
||||
if █x | continue | endif
|
||||
@@ -388,26 +393,28 @@ pressing `d]%` will produce (cursor on the `e`)
|
||||
if endif
|
||||
```
|
||||
|
||||
To include the close word, use either `dv]%` or `v]%d`. This is also
|
||||
To include the close word, use either `dv]%` or `v]%d`. This is also
|
||||
compatible with vim's `d])` and `d]}`.
|
||||
|
||||
Operators over _backward_ exclusive motions will instead exclude the
|
||||
position the cursor was on before the operator was invoked. For example,
|
||||
position the cursor was on before the operator was invoked. For example,
|
||||
in
|
||||
|
||||
```vim
|
||||
if █x | continue | endif
|
||||
```
|
||||
|
||||
pressing `d[%` will produce
|
||||
|
||||
```vim
|
||||
█x | continue | endif
|
||||
```
|
||||
|
||||
This is compatible with vim's `d[(` and `d[{`.
|
||||
|
||||
Unlike `]%`, `%` is an [inclusive] motion. As a special case for the
|
||||
Unlike `]%`, `%` is an [inclusive] motion. As a special case for the
|
||||
`d` (delete) operator, if `d%` leaves behind lines white-space, they will
|
||||
be deleted also. In effect, it will be operating line-wise. As an
|
||||
be deleted also. In effect, it will be operating line-wise. As an
|
||||
example, pressing `d%` will leave behind nothing.
|
||||
|
||||
```text
|
||||
@@ -421,35 +428,41 @@ This is vim compatible with the built-in `d%` on `matchpairs`.
|
||||
|
||||
### Line-wise operator/text-object combinations
|
||||
|
||||
Normally, the text objects `i%` and `a%` work character-wise. However,
|
||||
there are some special cases. For certain operators combined with `i%`,
|
||||
Normally, the text objects `i%` and `a%` work character-wise. However,
|
||||
there are some special cases. For certain operators combined with `i%`,
|
||||
under certain conditions, match-up will effectively operate line-wise
|
||||
instead. For example, in
|
||||
instead. For example, in
|
||||
|
||||
```vim
|
||||
if condition
|
||||
█call one()
|
||||
call two()
|
||||
endif
|
||||
```
|
||||
|
||||
pressing `di%` will produce
|
||||
|
||||
```vim
|
||||
if condition
|
||||
endif
|
||||
```
|
||||
even though deleting ` condition` would be suggested by the object `i%`.
|
||||
The intention is to make operators more useful in some cases. The
|
||||
following rules apply:
|
||||
1. The operator must be listed in `g:matchup_text_obj_linewise_operators`.
|
||||
By default this is `d` and `y` (e.g., `di%` and `ya%`).
|
||||
2. The outer block must span multiple lines.
|
||||
3. The open and close delimiters must be more than one character long. In
|
||||
particular, `di%` involving a `(`...`)` block will not be subject to
|
||||
these special rules.
|
||||
|
||||
To prevent this behavior for a particular operation, use `vi%d`. Note that
|
||||
even though deleting ` condition` would be suggested by the object `i%`.
|
||||
The intention is to make operators more useful in some cases. The
|
||||
following rules apply:
|
||||
|
||||
1. The operator must be listed in `g:matchup_text_obj_linewise_operators`.
|
||||
By default this is `d` and `y` (e.g., `di%` and `ya%`).
|
||||
2. The outer block must span multiple lines.
|
||||
3. The open and close delimiters must be more than one character long. In
|
||||
particular, `di%` involving a `(`...`)` block will not be subject to
|
||||
these special rules.
|
||||
|
||||
To prevent this behavior for a particular operation, use `vi%d`. Note that
|
||||
special cases involving indentation still apply (like with |i)| etc).
|
||||
|
||||
To disable this entirely, remove the operator from the following variable,
|
||||
|
||||
```vim
|
||||
let g:matchup_text_obj_linewise_operators = [ 'y' ]
|
||||
```
|
||||
@@ -457,71 +470,86 @@ let g:matchup_text_obj_linewise_operators = [ 'y' ]
|
||||
Note: unlike vim's built-in `i)`, `ab`, etc., `i%` does not make an
|
||||
existing visual mode character-wise.
|
||||
|
||||
A second special case involves `da%`. In this example,
|
||||
A second special case involves `da%`. In this example,
|
||||
|
||||
```vim
|
||||
if condition
|
||||
█call one()
|
||||
call two()
|
||||
endif
|
||||
```
|
||||
pressing `da%` will delete all four lines and leave no white-space. This
|
||||
|
||||
pressing `da%` will delete all four lines and leave no white-space. This
|
||||
is vim compatible with `da(`, `dab`, etc.
|
||||
|
||||
## Options
|
||||
|
||||
To disable the plugin entirely,
|
||||
|
||||
```vim
|
||||
let g:matchup_enabled = 0
|
||||
```
|
||||
|
||||
default: 1
|
||||
|
||||
To disable a particular module,
|
||||
|
||||
```vim
|
||||
let g:matchup_matchparen_enabled = 0
|
||||
let g:matchup_motion_enabled = 0
|
||||
let g:matchup_text_obj_enabled = 0
|
||||
```
|
||||
|
||||
defaults: 1
|
||||
|
||||
To enable the delete surrounding (`ds%`) and change surrounding (`cs%`)
|
||||
maps,
|
||||
|
||||
```vim
|
||||
let g:matchup_surround_enabled = 1
|
||||
```
|
||||
|
||||
default: 0
|
||||
|
||||
To enable the experimental
|
||||
[transmute](https://github.com/andymass/vim-matchup/blob/5a1978e46a0e721b5c5d113379c685ff7ec339e7/doc/matchup.txt#L311)
|
||||
module,
|
||||
|
||||
```vim
|
||||
let g:matchup_transmute_enabled = 1
|
||||
```
|
||||
|
||||
default: 0
|
||||
|
||||
To configure the number of lines to search in either direction while using
|
||||
motions and text objects. Does not apply to match highlighting
|
||||
motions and text objects. Does not apply to match highlighting
|
||||
(see `g:matchup_matchparen_stopline` instead).
|
||||
|
||||
```vim
|
||||
let g:matchup_delim_stopline = 1500
|
||||
```
|
||||
|
||||
default: 1500
|
||||
|
||||
To disable matching within strings and comments,
|
||||
|
||||
```vim
|
||||
let g:matchup_delim_noskips = 1 " recognize symbols within comments
|
||||
let g:matchup_delim_noskips = 2 " don't recognize anything in comments
|
||||
```
|
||||
|
||||
default: 0 (matching is enabled within strings and comments)
|
||||
|
||||
### Variables
|
||||
|
||||
match-up understands the following variables from matchit.
|
||||
|
||||
- `b:match_words`
|
||||
- `b:match_skip`
|
||||
- `b:match_ignorecase`
|
||||
|
||||
These are set in the respective ftplugin files. They may not exist for
|
||||
every file type. To support a new file type, create a file
|
||||
These are set in the respective ftplugin files. They may not exist for
|
||||
every file type. To support a new file type, create a file
|
||||
`after/ftplugin/{filetype}.vim` which sets them appropriately.
|
||||
|
||||
### Module matchparen
|
||||
@@ -534,13 +562,15 @@ The variable `g:loaded_matchparen` has no effect on match-up.
|
||||
#### Customizing the highlighting colors
|
||||
|
||||
match-up uses the `MatchParen` highlighting group by default, which can be
|
||||
configured. For example,
|
||||
configured. For example,
|
||||
|
||||
```vim
|
||||
:hi MatchParen ctermbg=blue guibg=lightblue cterm=italic gui=italic
|
||||
```
|
||||
|
||||
You may want to put this inside a `ColorScheme` `autocmd` so it is
|
||||
preserved after colorscheme changes:
|
||||
|
||||
```vim
|
||||
augroup matchup_matchparen_highlight
|
||||
autocmd!
|
||||
@@ -549,39 +579,45 @@ augroup END
|
||||
```
|
||||
|
||||
You can also highlight words differently than parentheses using the
|
||||
`MatchWord` highlighting group. You might do this if you find the
|
||||
`MatchWord` highlighting group. You might do this if you find the
|
||||
`MatchParen` style distracting for large blocks.
|
||||
|
||||
```vim
|
||||
:hi MatchWord ctermfg=red guifg=blue cterm=underline gui=underline
|
||||
```
|
||||
|
||||
There are also `MatchParenCur` and `MatchWordCur` which allow you to
|
||||
configure the highlight separately for the match under the cursor.
|
||||
|
||||
```vim
|
||||
:hi MatchParenCur cterm=underline gui=underline
|
||||
:hi MatchWordCur cterm=underline gui=underline
|
||||
```
|
||||
|
||||
The matchparen module can be disabled on a per-buffer basis (there is
|
||||
no command for this). By default, when disabling highlighting for a
|
||||
no command for this). By default, when disabling highlighting for a
|
||||
particular buffer, the standard plugin matchparen will still be used
|
||||
for that buffer.
|
||||
|
||||
```vim
|
||||
let b:matchup_matchparen_enabled = 0
|
||||
```
|
||||
|
||||
default: 1
|
||||
|
||||
If this module is disabled on a particular buffer, match-up will still
|
||||
fall-back to the vim standard plugin matchparen, which will highlight
|
||||
`matchpairs` such as `()`, `[]`, & `{}`. To disable this,
|
||||
`matchpairs` such as `()`, `[]`, & `{}`. To disable this,
|
||||
|
||||
```vim
|
||||
let b:matchup_matchparen_fallback = 0
|
||||
```
|
||||
|
||||
default: 1
|
||||
|
||||
A common usage of these options is to automatically disable
|
||||
matchparen for particular file types;
|
||||
|
||||
```vim
|
||||
augroup matchup_matchparen_disable_ft
|
||||
autocmd!
|
||||
@@ -591,19 +627,22 @@ augroup END
|
||||
```
|
||||
|
||||
Whether to highlight known words even if there is no match:
|
||||
|
||||
```vim
|
||||
let g:matchup_matchparen_singleton = 1
|
||||
```
|
||||
|
||||
default: 0
|
||||
|
||||
Dictionary controlling the behavior with off-screen matches.
|
||||
|
||||
```vim
|
||||
let g:matchup_matchparen_offscreen = { ... }
|
||||
```
|
||||
|
||||
default: `{'method': 'status'}`
|
||||
|
||||
If empty, this feature is disabled. Else, it should contain the
|
||||
If empty, this feature is disabled. Else, it should contain the
|
||||
following optional keys:
|
||||
|
||||
- `method`:
|
||||
@@ -614,15 +653,15 @@ following optional keys:
|
||||
|
||||
If a match is off of the screen, the line belonging to that match will be
|
||||
displayed syntax-highlighted in the status line along with the line number
|
||||
(if line numbers are enabled). If the match is above the screen border,
|
||||
(if line numbers are enabled). If the match is above the screen border,
|
||||
an additional Δ symbol will be shown to indicate that the matching line is
|
||||
really above the cursor line.
|
||||
|
||||
`'popup'`: Show off-screen matches in a popup (vim) or
|
||||
floating (neovim) window.
|
||||
floating (Neovim) window.
|
||||
|
||||
`'status_manual'`: Compute the string which would be displayed in the
|
||||
status-line or popup, but do not display it. The function
|
||||
status-line or popup, but do not display it. The function
|
||||
`MatchupStatusOffscreen()` can be used to get the text.
|
||||
|
||||
- `scrolloff`:
|
||||
@@ -633,8 +672,9 @@ following optional keys:
|
||||
default: 0.
|
||||
|
||||
The number of lines to search in either direction while highlighting
|
||||
matches. Set this conservatively since high values may cause performance
|
||||
matches. Set this conservatively since high values may cause performance
|
||||
issues.
|
||||
|
||||
```vim
|
||||
let g:matchup_matchparen_stopline = 400 " for match highlighting only
|
||||
```
|
||||
@@ -644,10 +684,12 @@ default: 400
|
||||
#### highlighting timeouts
|
||||
|
||||
Adjust timeouts in milliseconds for matchparen highlighting:
|
||||
|
||||
```vim
|
||||
let g:matchup_matchparen_timeout = 300
|
||||
let g:matchup_matchparen_insert_timeout = 60
|
||||
```
|
||||
|
||||
default: 300, 60
|
||||
|
||||
#### deferred highlighting
|
||||
@@ -655,19 +697,23 @@ default: 300, 60
|
||||
Deferred highlighting improves cursor movement performance (for example,
|
||||
when using `hjkl`) by delaying highlighting for a short time and waiting
|
||||
to see if the cursor continues moving;
|
||||
|
||||
```vim
|
||||
let g:matchup_matchparen_deferred = 1
|
||||
```
|
||||
|
||||
default: 0 (disabled)
|
||||
|
||||
Note: this feature is only available if your vim version has `timers` and
|
||||
the function `timer_pause`, version 7.4.2180 and after.
|
||||
|
||||
Adjust delays in milliseconds for deferred highlighting:
|
||||
|
||||
```vim
|
||||
let g:matchup_matchparen_deferred_show_delay = 50
|
||||
let g:matchup_matchparen_deferred_hide_delay = 700
|
||||
```
|
||||
|
||||
default: 50, 700
|
||||
|
||||
Note: these delays cannot be changed dynamically and should be configured
|
||||
@@ -677,19 +723,24 @@ before the plugin loads (e.g., in your vimrc).
|
||||
|
||||
To highlight the surrounding delimiters until the cursor moves, use a map
|
||||
such as the following
|
||||
|
||||
```vim
|
||||
nmap <silent> <F7> <plug>(matchup-hi-surround)
|
||||
```
|
||||
|
||||
There is no default map for this feature.
|
||||
|
||||
You can also highlight surrounding delimiters always as the cursor moves.
|
||||
|
||||
```vim
|
||||
let g:matchup_matchparen_deferred = 1
|
||||
let g:matchup_matchparen_hi_surround_always = 1
|
||||
```
|
||||
|
||||
default: 0 (off)
|
||||
|
||||
This can be set on a per-buffer basis:
|
||||
|
||||
```vim
|
||||
autocmd FileType tex let b:matchup_matchparen_hi_surround_always = 1
|
||||
```
|
||||
@@ -702,43 +753,53 @@ enabled.
|
||||
|
||||
In vim, `{count}%` goes to the `{count}` percentage in the file.
|
||||
match-up overrides this motion for small `{count}` (by default, anything
|
||||
less than 7). To allow `{count}%` for `{count}` less than 12,
|
||||
less than 7). To allow `{count}%` for `{count}` less than 12,
|
||||
|
||||
```vim
|
||||
g:matchup_motion_override_Npercent = 11
|
||||
```
|
||||
|
||||
To disable this feature, and restore vim's default `{count}%`,
|
||||
|
||||
```vim
|
||||
g:matchup_motion_override_Npercent = 0
|
||||
```
|
||||
|
||||
To always enable this feature, use any value greater than 99,
|
||||
|
||||
```vim
|
||||
g:matchup_motion_override_Npercent = 100
|
||||
```
|
||||
|
||||
default: 6
|
||||
|
||||
If enabled, cursor will land on the end of mid and close words while
|
||||
moving downwards (`%`/`]%`). While moving upwards (`g%`, `[%`) the cursor
|
||||
will land on the beginning. To disable,
|
||||
moving downwards (`%`/`]%`). While moving upwards (`g%`, `[%`) the cursor
|
||||
will land on the beginning. To disable,
|
||||
|
||||
```vim
|
||||
let g:matchup_motion_cursor_end = 0
|
||||
```
|
||||
|
||||
default: 1
|
||||
|
||||
### Module text_obj
|
||||
|
||||
Modify the set of operators which may operate
|
||||
[line-wise](#line-wise-operatortext-object-combinations)
|
||||
|
||||
```vim
|
||||
let g:matchup_text_obj_linewise_operators = ['d', 'y']
|
||||
```
|
||||
|
||||
default: `['d', 'y']`
|
||||
|
||||
## FAQ
|
||||
|
||||
- match-up doesn't work
|
||||
|
||||
This plugin requires at least vim 7.4. It should work in vim 7.4.898
|
||||
but at least vim 7.4.1689 is better. I recommend using the most recent
|
||||
This plugin requires at least vim 7.4. It should work in vim 7.4.898
|
||||
but at least vim 7.4.1689 is better. I recommend using the most recent
|
||||
version of vim if possible.
|
||||
|
||||
If you have issues, please tell me your vim version and error messages.
|
||||
@@ -760,7 +821,7 @@ default: `['d', 'y']`
|
||||
- Highlighting is not correct for construct X
|
||||
|
||||
match-up uses matchit's filetype-specific data, which may not give
|
||||
enough information to create proper highlights. To fix this, you may
|
||||
enough information to create proper highlights. To fix this, you may
|
||||
need to modify `b:match_words` in your configuration.
|
||||
|
||||
For more help, please open a new issue and be as specific as possible.
|
||||
@@ -768,17 +829,17 @@ default: `['d', 'y']`
|
||||
- I'm having performance problems
|
||||
|
||||
match-up aims to be as fast as possible, but highlighting matching words
|
||||
can be intensive and may be slow on less powerful machines. There are a
|
||||
can be intensive and may be slow on less powerful machines. There are a
|
||||
few things you can try to improve performance:
|
||||
|
||||
1. Update to a recent version of vim. Newer versions are faster, more
|
||||
extensively tested, and better supported by match-up.
|
||||
1. Update to a recent version of vim. Newer versions are faster, more
|
||||
extensively tested, and better supported by match-up.
|
||||
2. Try [deferred highlighting](#deferred-highlighting), which delays
|
||||
highlighting until the cursor is stationary to improve cursor movement
|
||||
performance.
|
||||
3. Lower the [highlighting timeouts](#highlighting-timeouts). Note that
|
||||
if highlighting takes longer than the timeout, highlighting will not be
|
||||
attempted again until the cursor moves.
|
||||
highlighting until the cursor is stationary to improve cursor movement
|
||||
performance.
|
||||
3. Lower the [highlighting timeouts](#highlighting-timeouts). Note that
|
||||
if highlighting takes longer than the timeout, highlighting will not be
|
||||
attempted again until the cursor moves.
|
||||
|
||||
If are having any other performance issues, please open a new issue and
|
||||
report the output of `:MatchupShowTimes`.
|
||||
@@ -786,7 +847,7 @@ default: `['d', 'y']`
|
||||
- Why is there a weird entry on the status line?
|
||||
|
||||
This is a feature which helps you see matches that are outside of the
|
||||
vim screen, similar to some IDEs. If you wish to disable it, use
|
||||
vim screen, similar to some IDEs. If you wish to disable it, use
|
||||
|
||||
```vim
|
||||
let g:matchup_matchparen_offscreen = {}
|
||||
@@ -794,13 +855,14 @@ default: `['d', 'y']`
|
||||
|
||||
- Matching does not work when lines are too far apart.
|
||||
|
||||
The number of search lines is limited for performance reasons. You may
|
||||
The number of search lines is limited for performance reasons. You may
|
||||
increase the limits with the following options:
|
||||
|
||||
```vim
|
||||
let g:matchup_delim_stopline = 1500 " generally
|
||||
let g:matchup_matchparen_stopline = 400 " for match highlighting only
|
||||
```
|
||||
|
||||
- The maps `1i%` and `1a%` are difficult to press.
|
||||
|
||||
You may use the following maps `I%` and `A%` for convenience:
|
||||
@@ -824,7 +886,7 @@ default: `['d', 'y']`
|
||||
- How can I contribute?
|
||||
|
||||
Read the [contribution guidelines](CONTRIBUTING.md) and [issue
|
||||
template](.github/ISSUE_TEMPLATE/bug_report.md). Be as precise and
|
||||
template](.github/ISSUE_TEMPLATE/bug_report.md). Be as precise and
|
||||
detailed as possible
|
||||
when submitting issues and pull requests.
|
||||
|
||||
@@ -833,15 +895,15 @@ default: `['d', 'y']`
|
||||
### vimtex, for LaTeX documents
|
||||
|
||||
By default, match-up will be disabled automatically for tex files when
|
||||
[vimtex] is detected. To enable match-up for tex files, use
|
||||
[vimtex] is detected. To enable match-up for tex files, use
|
||||
|
||||
```vim
|
||||
let g:matchup_override_vimtex = 1
|
||||
```
|
||||
|
||||
match-up's matching engine is more advanced than vimtex's and supports
|
||||
middle delimiters such as `\middle|` and `\else`. The exact set of
|
||||
delimiters recognized may differ between the two plugins. For example,
|
||||
middle delimiters such as `\middle|` and `\else`. The exact set of
|
||||
delimiters recognized may differ between the two plugins. For example,
|
||||
the mappings `da%` and `dad` will not always match, particularly if you
|
||||
have customized vimtex's delimiters.
|
||||
|
||||
@@ -850,7 +912,7 @@ have customized vimtex's delimiters.
|
||||
match-up provides built-in support for [vim-surround]-style `ds%` and
|
||||
`cs%` operations (`let g:matchup_surround_enabled = 1`).
|
||||
If vim-surround is installed, you can use vim-surround
|
||||
replacements such as `cs%)`. `%` cannot be used as a replacement.
|
||||
replacements such as `cs%)`. `%` cannot be used as a replacement.
|
||||
An alternative plugin is [vim-sandwich], which allows more complex
|
||||
surround replacement rules but is not currently supported.
|
||||
|
||||
@@ -873,23 +935,23 @@ See for instance one of the following plugins for this;
|
||||
match-up tries to work around matchit.vim in all cases, but if
|
||||
you experience problems, read the following:
|
||||
|
||||
- For vim, matchit.vim should not be loaded. If it is loaded, it should
|
||||
- For vim, matchit.vim should not be loaded. If it is loaded, it should
|
||||
be loaded after match-up (in this case, matchit.vim will be disabled).
|
||||
Note that some plugins, such as
|
||||
[vim-sensible](https://github.com/tpope/vim-sensible), load matchit.vim
|
||||
so these should also be initialized after match-up.
|
||||
|
||||
- For neovim, matchit.vim is loaded by default. This should not cause any
|
||||
- For Neovim, matchit.vim is loaded by default. This should not cause any
|
||||
problems, but you may see a very slight start-up time improvement by
|
||||
setting `let g:loaded_matchit = 1` in your `init.vim`.
|
||||
|
||||
### Matchparen emulation
|
||||
|
||||
match-up loads [matchparen] if it is not already loaded. Ordinarily, match-up
|
||||
match-up loads [matchparen] if it is not already loaded. Ordinarily, match-up
|
||||
disables matchparen's highlighting and emulates it to highlight the symbol
|
||||
contained in the 'matchpairs' option (by default `()`, `[]`, and `{}`). If match-up
|
||||
contained in the 'matchpairs' option (by default `()`, `[]`, and `{}`). If match-up
|
||||
is disabled per-buffer using `b:matchup_matchparen_enabled`, match-up will use
|
||||
matchparen instead of its own highlighting. See `b:matchup_matchparen_fallback`
|
||||
matchparen instead of its own highlighting. See `b:matchup_matchparen_fallback`
|
||||
for more information.
|
||||
|
||||
## Acknowledgments
|
||||
@@ -897,7 +959,7 @@ for more information.
|
||||
### Origins
|
||||
|
||||
match-up was originally based on [@lervag](https://github.com/lervag)'s
|
||||
[vimtex]. The concept and style of this plugin and its development are
|
||||
[vimtex]. The concept and style of this plugin and its development are
|
||||
heavily influenced by vimtex. :beers:
|
||||
|
||||
[vimtex]: https://github.com/lervag/vimtex
|
||||
@@ -914,8 +976,8 @@ heavily influenced by vimtex. :beers:
|
||||
|
||||
### Reporting problems
|
||||
|
||||
Thorough issue reports are encouraged. Please read the [issue
|
||||
template](.github/ISSUE_TEMPLATE/bug_report.md) first. Be as precise and
|
||||
Thorough issue reports are encouraged. Please read the [issue
|
||||
template](.github/ISSUE_TEMPLATE/bug_report.md) first. Be as precise and
|
||||
detailed as
|
||||
possible when submitting issues.
|
||||
|
||||
@@ -927,4 +989,3 @@ Please read the [contribution guidelines](CONTRIBUTING.md) before
|
||||
contributing.
|
||||
|
||||
Contributions are welcome!
|
||||
|
||||
|
||||
@@ -20,8 +20,11 @@
|
||||
(do_group
|
||||
"done" @close.loop)) @scope.loop
|
||||
|
||||
((word) @mid.loop.1 (#eq? @mid.loop.1 "break"))
|
||||
((word) @mid.loop.2 (#eq? @mid.loop.2 "continue"))
|
||||
((word) @mid.loop.1
|
||||
(#eq? @mid.loop.1 "break"))
|
||||
|
||||
((word) @mid.loop.2
|
||||
(#eq? @mid.loop.2 "continue"))
|
||||
|
||||
(case_statement
|
||||
"case" @open.case
|
||||
@@ -29,5 +32,9 @@
|
||||
"esac" @close.case) @scope.case
|
||||
|
||||
(heredoc_redirect
|
||||
(heredoc_start) @open.rhrd
|
||||
(heredoc_end ) @close.rhrd) @scope.rhrd
|
||||
(heredoc_start) @open.rhrd
|
||||
(heredoc_end) @close.rhrd) @scope.rhrd
|
||||
|
||||
(compound_statement
|
||||
"{" @open.block
|
||||
"}" @close.block) @scope.block
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
; inherits: quote
|
||||
|
||||
(preproc_ifdef
|
||||
["#ifdef" "#ifndef"] @open.def
|
||||
[
|
||||
"#ifdef"
|
||||
"#ifndef"
|
||||
] @open.def
|
||||
"#endif" @close.def) @scope.def
|
||||
|
||||
(preproc_if
|
||||
"#if" @open.def
|
||||
"#endif" @close.def) @scope.def
|
||||
|
||||
(preproc_elif "#elif" @mid.def.1)
|
||||
(preproc_else "#else" @mid.def.2)
|
||||
(preproc_elif
|
||||
"#elif" @mid.def.1)
|
||||
|
||||
(preproc_else
|
||||
"#else" @mid.def.2)
|
||||
|
||||
(switch_statement
|
||||
"switch" @open.switch
|
||||
body: (compound_statement
|
||||
(case_statement "case" @mid.switch.1)?
|
||||
(case_statement "default" @mid.switch.2)?)) @scope.switch
|
||||
(case_statement
|
||||
"case" @mid.switch.1)?
|
||||
(case_statement
|
||||
"default" @mid.switch.2)?)) @scope.switch
|
||||
|
||||
; 'else' and 'else if'
|
||||
(else_clause
|
||||
"else" @_start (if_statement "if" @_end)?
|
||||
(#make-range! "mid.if.1" @_start @_end))
|
||||
"else" @mid.if.1
|
||||
(if_statement
|
||||
"if" @mid.if.1)?)
|
||||
|
||||
; if
|
||||
((if_statement
|
||||
"if" @open.if) @scope.if
|
||||
(#not-has-parent? @scope.if else_clause))
|
||||
|
||||
(#not-has-parent? @scope.if else_clause))
|
||||
|
||||
; if
|
||||
(compound_statement
|
||||
@@ -35,11 +43,31 @@
|
||||
|
||||
; Functions
|
||||
(function_definition) @scope.function
|
||||
(function_declarator declarator: (identifier) @open.function)
|
||||
(return_statement "return" @mid.function.1)
|
||||
|
||||
(function_declarator
|
||||
declarator: (identifier) @open.function)
|
||||
|
||||
(return_statement
|
||||
"return" @mid.function.1)
|
||||
|
||||
; Loops
|
||||
(for_statement "for" @open.loop) @scope.loop
|
||||
(while_statement "while" @open.loop) @scope.loop
|
||||
(do_statement "do" @open.loop "while" @close.loop) @scope.loop
|
||||
(break_statement "break" @mid.loop.1)
|
||||
(for_statement
|
||||
"for" @open.loop) @scope.loop
|
||||
|
||||
(while_statement
|
||||
"while" @open.loop) @scope.loop
|
||||
|
||||
(do_statement
|
||||
"do" @open.loop
|
||||
"while" @close.loop) @scope.loop
|
||||
|
||||
(break_statement
|
||||
"break" @mid.loop.1)
|
||||
|
||||
(compound_statement
|
||||
"{" @open.block
|
||||
"}" @close.block) @scope.block
|
||||
|
||||
(argument_list
|
||||
"(" @open.call
|
||||
")" @close.call) @scope.call
|
||||
|
||||
@@ -2,35 +2,57 @@
|
||||
|
||||
; functions
|
||||
[
|
||||
(arrow_function "=>" @open.function)
|
||||
(function_expression "function" @open.function)
|
||||
(function_declaration "function" @open.function)
|
||||
(method_definition body: (statement_block "{" @open.function "}" @close.function))
|
||||
(arrow_function
|
||||
"=>" @open.function)
|
||||
(function_expression
|
||||
"function" @open.function)
|
||||
(function_declaration
|
||||
"function" @open.function)
|
||||
(method_definition
|
||||
body: (statement_block
|
||||
"{" @open.function
|
||||
"}" @close.function))
|
||||
] @scope.function
|
||||
|
||||
(return_statement "return" @mid.function.1)
|
||||
(statement_block
|
||||
"{" @open.block
|
||||
"}" @close.block) @scope.block
|
||||
|
||||
(return_statement
|
||||
"return" @mid.function.1)
|
||||
|
||||
; switch case
|
||||
(switch_statement "switch" @open.switch) @scope.switch
|
||||
(switch_case "case" @mid.switch.1)
|
||||
(switch_default "default" @mid.switch.2)
|
||||
(switch_statement
|
||||
"switch" @open.switch) @scope.switch
|
||||
|
||||
(switch_case
|
||||
"case" @mid.switch.1)
|
||||
|
||||
(switch_default
|
||||
"default" @mid.switch.2)
|
||||
|
||||
; 'else' and 'else if'
|
||||
(else_clause
|
||||
"else" @_start (if_statement "if" @_end)?
|
||||
(#make-range! "mid.if.1" @_start @_end))
|
||||
"else" @mid.if.1
|
||||
(if_statement
|
||||
"if" @mid.if.1)?)
|
||||
|
||||
; if
|
||||
((if_statement
|
||||
"if" @open.if) @scope.if
|
||||
(#not-has-parent? @scope.if else_clause))
|
||||
(#not-has-parent? @scope.if else_clause))
|
||||
|
||||
; try
|
||||
(try_statement "try" @open.try) @scope.try
|
||||
(catch_clause "catch" @mid.try.1)
|
||||
(finally_clause "finally" @mid.try.2)
|
||||
(try_statement
|
||||
"try" @open.try) @scope.try
|
||||
|
||||
(catch_clause
|
||||
"catch" @mid.try.1)
|
||||
|
||||
(finally_clause
|
||||
"finally" @mid.try.2)
|
||||
|
||||
; template strings
|
||||
(template_string
|
||||
"`" @open.tmpl_str
|
||||
"`" @close.tmpl_str) @scope.tmpl_str
|
||||
"`" @open.tmpl_str
|
||||
"`" @close.tmpl_str) @scope.tmpl_str
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(if_else_expr
|
||||
. "if" @open.if) @scope.if
|
||||
.
|
||||
"if" @open.if) @scope.if
|
||||
|
||||
(if_else_expr
|
||||
"else" @_else
|
||||
"if"? @_if
|
||||
(#make-range! "mid.if.1" @_else @_if))
|
||||
"else" @mid.if.1
|
||||
"if"? @mid.if.1)
|
||||
|
||||
(let_in_expr
|
||||
"let" @open.let
|
||||
@@ -13,4 +13,4 @@
|
||||
(case_of_expr
|
||||
(case) @open.case
|
||||
(case_of_branch
|
||||
(arrow) @mid.case.1)) @scope.case
|
||||
(arrow) @mid.case.1)) @scope.case
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
(if_statement
|
||||
"if" @open.if
|
||||
(else_if_clause ("else" "if") @mid.if.1)?
|
||||
(else_clause "else" @mid.if.2)?
|
||||
"end" @close.if
|
||||
) @scope.if
|
||||
(else_if_clause
|
||||
("else"
|
||||
"if") @mid.if.1)?
|
||||
(else_clause
|
||||
"else" @mid.if.2)?
|
||||
"end" @close.if) @scope.if
|
||||
|
||||
(switch_statement
|
||||
"switch" @open.switch
|
||||
(case_clause "case" @mid.switch.1)?
|
||||
"end" @close.switch
|
||||
) @scope.switch
|
||||
(case_clause
|
||||
"case" @mid.switch.1)?
|
||||
"end" @close.switch) @scope.switch
|
||||
|
||||
(for_statement
|
||||
"for" @open.loop
|
||||
"in" @mid.loop.1
|
||||
"end" @close.loop) @scope.loop
|
||||
|
||||
((break) @mid.loop.2)?
|
||||
|
||||
((continue) @mid.loop.3)?
|
||||
|
||||
(while_statement
|
||||
@@ -29,4 +33,6 @@
|
||||
(function_definition
|
||||
"function" @open.func
|
||||
"end" @close.func) @scope.func
|
||||
(return "return" @mid.func.1)
|
||||
|
||||
(return
|
||||
"return" @mid.func.1)
|
||||
|
||||
@@ -2,33 +2,42 @@
|
||||
|
||||
(element_node) @scope.tag
|
||||
|
||||
(element_node_start (tag_name) @open.tag)
|
||||
(element_node_start
|
||||
(tag_name) @open.tag)
|
||||
|
||||
(element_node_end
|
||||
(tag_name) @close.tag
|
||||
(#offset! @close.tag 0 -1 0 0))
|
||||
|
||||
(block_statement
|
||||
(block_statement_start) @open.block
|
||||
(block_statement_end) @close.block
|
||||
) @scope.block
|
||||
(block_statement_end) @close.block) @scope.block
|
||||
|
||||
; {{else if ...}}
|
||||
(mustache_statement
|
||||
(helper_invocation helper: (identifier) @mid.block.1 (#lua-match? @mid.block.1 "else"))
|
||||
)
|
||||
(helper_invocation
|
||||
helper: (identifier) @mid.block.1
|
||||
(#lua-match? @mid.block.1 "else")))
|
||||
|
||||
; {{else}}
|
||||
(mustache_statement ((identifier) @mid.block.2 (#lua-match? @mid.block.2 "else")))
|
||||
(mustache_statement
|
||||
((identifier) @mid.block.2
|
||||
(#lua-match? @mid.block.2 "else")))
|
||||
|
||||
(element_node_void
|
||||
(tag_name) @open.selftag
|
||||
"/>" @close.selftag
|
||||
) @scope.selftag
|
||||
"/>" @close.selftag) @scope.selftag
|
||||
|
||||
(mustache_statement
|
||||
[(helper_invocation) "{{"] @open.mustache
|
||||
"}}" @close.mustache
|
||||
) @scope.mustache
|
||||
[
|
||||
(helper_invocation)
|
||||
"{{"
|
||||
] @open.mustache
|
||||
"}}" @close.mustache) @scope.mustache
|
||||
|
||||
(sub_expression
|
||||
[(helper_invocation) "("] @open.subexpr
|
||||
")" @close.subexpr
|
||||
) @scope.subexpr
|
||||
[
|
||||
(helper_invocation)
|
||||
"("
|
||||
] @open.subexpr
|
||||
")" @close.subexpr) @scope.subexpr
|
||||
|
||||
@@ -1,22 +1,42 @@
|
||||
(function_declaration "func" @open.func) @scope.func
|
||||
(method_declaration "func" @open.func) @scope.func
|
||||
(func_literal "func" @open.func) @scope.func
|
||||
(function_declaration
|
||||
"func" @open.func) @scope.func
|
||||
|
||||
(return_statement "return" @mid.func.1)
|
||||
(method_declaration
|
||||
"func" @open.func) @scope.func
|
||||
|
||||
(func_literal
|
||||
"func" @open.func) @scope.func
|
||||
|
||||
(return_statement
|
||||
"return" @mid.func.1)
|
||||
|
||||
; 'else' and 'else if'
|
||||
(if_statement
|
||||
"else" @_start (if_statement "if" @_end)?
|
||||
(#make-range! "mid.if.1" @_start @_end))
|
||||
"else" @mid.if.1
|
||||
(if_statement
|
||||
"if" @mid.if.1)?)
|
||||
|
||||
; if
|
||||
(block (if_statement "if" @open.if) @scope.if)
|
||||
(block
|
||||
(if_statement
|
||||
"if" @open.if) @scope.if)
|
||||
|
||||
; switch
|
||||
(expression_switch_statement "switch" @open.switch
|
||||
(expression_case "case" @mid.switch.1)
|
||||
(default_case "default" @mid.switch.2)) @scope.switch
|
||||
(expression_switch_statement
|
||||
"switch" @open.switch
|
||||
(expression_case
|
||||
"case" @mid.switch.1)
|
||||
(default_case
|
||||
"default" @mid.switch.2)) @scope.switch
|
||||
|
||||
(_
|
||||
"\"" @open.quote_double
|
||||
"\"" @close.quote_double) @scope.quote_double
|
||||
|
||||
(block
|
||||
"{" @open.block
|
||||
"}" @close.block) @scope.block
|
||||
|
||||
(argument_list
|
||||
"(" @open.call
|
||||
")" @close.call) @scope.call
|
||||
|
||||
@@ -1,73 +1,67 @@
|
||||
; --------------- module/where ---------------
|
||||
(header (
|
||||
("module" @open.module (module))
|
||||
("where" @mid.module.1)
|
||||
)) @scope.module
|
||||
(header
|
||||
(("module" @open.module
|
||||
(module))
|
||||
"where" @mid.module.1)) @scope.module
|
||||
|
||||
; ----------------- case/of ------------------
|
||||
(expression/case
|
||||
"case" @open.case (_)
|
||||
(expression/case
|
||||
"case" @open.case
|
||||
(_)
|
||||
"of" @mid.case.1
|
||||
(alternatives
|
||||
(alternative) @mid.case.2
|
||||
)
|
||||
) @scope.case
|
||||
(alternative) @mid.case.2)) @scope.case
|
||||
|
||||
; --------------- lambda case ----------------
|
||||
(expression/lambda_case
|
||||
"\case" @open.case
|
||||
(expression/lambda_case
|
||||
"\\case" @open.case
|
||||
(alternatives
|
||||
(alternative) @mid.case.1
|
||||
)
|
||||
) @scope.case
|
||||
(alternative) @mid.case.1)) @scope.case
|
||||
|
||||
; -------------- if/then/else ----------------
|
||||
(expression/conditional
|
||||
"if" @open.if (_)
|
||||
"then" @mid.if.1 (_)
|
||||
"else" @mid.if.2 (_)
|
||||
) @scope.if
|
||||
"if" @open.if
|
||||
(_)
|
||||
"then" @mid.if.1
|
||||
(_)
|
||||
"else" @mid.if.2
|
||||
(_)) @scope.if
|
||||
|
||||
;------------------ let/in -------------------
|
||||
(expression/let_in
|
||||
("let" @open.let (local_binds))
|
||||
("in" @mid.let.1 (_))
|
||||
) @scope.let
|
||||
("let" @open.let
|
||||
(local_binds))
|
||||
("in" @mid.let.1
|
||||
(_))) @scope.let
|
||||
|
||||
; -------- ADT data/constructors -------------
|
||||
(data_type
|
||||
"data" @open.adt (_)
|
||||
"data" @open.adt
|
||||
(_)
|
||||
constructors: (data_constructors
|
||||
(data_constructor
|
||||
constructor: (_) @mid.adt.2
|
||||
))
|
||||
) @scope.adt
|
||||
constructor: (_) @mid.adt.2))) @scope.adt
|
||||
|
||||
; --------------- ADT record ------------------
|
||||
(data_type
|
||||
"data" @open.rec (_)
|
||||
"data" @open.rec
|
||||
(_)
|
||||
constructors: (data_constructors
|
||||
constructor: (data_constructor
|
||||
(record
|
||||
fields: (fields
|
||||
"{" @mid.rec.1 (_)
|
||||
"}" @mid.rec.2
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
) @scope.rec
|
||||
"{" @mid.rec.1
|
||||
(_)
|
||||
"}" @mid.rec.2))))) @scope.rec
|
||||
|
||||
; ------------- GADT data/where ---------------
|
||||
(data_type
|
||||
"data" @open.gadt (_)
|
||||
"data" @open.gadt
|
||||
(_)
|
||||
"where" @mid.gadt.1
|
||||
constructors: (gadt_constructors
|
||||
constructor: (gadt_constructor
|
||||
name: (constructor) @mid.gadt.2
|
||||
)
|
||||
)
|
||||
) @scope.gadt
|
||||
name: (constructor) @mid.gadt.2))) @scope.gadt
|
||||
|
||||
; --------------- class/where -----------------
|
||||
(class
|
||||
@@ -75,7 +69,4 @@
|
||||
"where" @mid.class.1
|
||||
declarations: (class_declarations
|
||||
declaration: (_
|
||||
name: (variable) @mid.class.2
|
||||
)
|
||||
)
|
||||
) @scope.class
|
||||
name: (variable) @mid.class.2))) @scope.class
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
; inherits: quote
|
||||
|
||||
[
|
||||
(element)
|
||||
(script_element)
|
||||
(style_element)
|
||||
(element)
|
||||
(script_element)
|
||||
(style_element)
|
||||
] @scope.tag
|
||||
|
||||
(start_tag (tag_name) @open.tag)
|
||||
(start_tag
|
||||
(tag_name) @open.tag)
|
||||
|
||||
(end_tag
|
||||
(tag_name) @close.tag
|
||||
(#offset! @close.tag 0 -1 0 0))
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
(jsx_element) @scope.tag
|
||||
(jsx_opening_element (identifier) @open.tag)
|
||||
|
||||
(jsx_opening_element
|
||||
(identifier) @open.tag)
|
||||
|
||||
(jsx_closing_element
|
||||
(identifier) @close.tag
|
||||
(#offset! @close.tag 0 -1 0 0))
|
||||
|
||||
@@ -1,35 +1,46 @@
|
||||
(function_definition
|
||||
"function" @open.function
|
||||
"end" @close.function) @scope.function
|
||||
|
||||
(return_statement
|
||||
"return" @mid.function.1)
|
||||
|
||||
(if_statement
|
||||
"if" @open.if
|
||||
"end" @close.if) @scope.if
|
||||
(else_clause "else" @mid.if.1)
|
||||
(elseif_clause "elseif" @mid.if.2)
|
||||
|
||||
(else_clause
|
||||
"else" @mid.if.1)
|
||||
|
||||
(elseif_clause
|
||||
"elseif" @mid.if.2)
|
||||
|
||||
(for_statement
|
||||
"for" @open.loop
|
||||
"end" @close.loop) @scope.loop
|
||||
|
||||
(while_statement
|
||||
"while" @open.loop
|
||||
"end" @close.loop) @scope.loop
|
||||
|
||||
(break_statement) @mid.loop.1
|
||||
|
||||
(continue_statement) @mid.loop.2
|
||||
|
||||
(try_statement
|
||||
"try" @open.try
|
||||
"end" @close.try) @scope.try
|
||||
|
||||
(catch_clause
|
||||
"catch" @mid.try.2)
|
||||
|
||||
(finally_clause
|
||||
"finally" @mid.try.1)
|
||||
|
||||
(compound_statement
|
||||
"begin" @open.block
|
||||
"end" @close.block) @scope.block
|
||||
|
||||
(do_clause
|
||||
"do" @open.block
|
||||
"end" @close.block) @scope.block
|
||||
@@ -37,6 +48,7 @@
|
||||
(let_statement
|
||||
"let" @open.let
|
||||
"end" @close.let) @scope.let
|
||||
|
||||
(module_definition
|
||||
"module" @open.module
|
||||
"end" @close.module) @scope.module
|
||||
|
||||
@@ -13,12 +13,17 @@
|
||||
(if_statement
|
||||
"if" @open.if
|
||||
"end" @close.if) @scope.if
|
||||
(else_statement "else" @mid.if.1)
|
||||
(elseif_statement "elseif" @mid.if.2)
|
||||
|
||||
(else_statement
|
||||
"else" @mid.if.1)
|
||||
|
||||
(elseif_statement
|
||||
"elseif" @mid.if.2)
|
||||
|
||||
(function_declaration
|
||||
"function" @open.function
|
||||
"end" @close.function) @scope.function
|
||||
|
||||
(function_definition
|
||||
"function" @open.function
|
||||
"end" @close.function) @scope.function
|
||||
@@ -29,3 +34,12 @@
|
||||
(do_statement
|
||||
"do" @open.block
|
||||
"end" @close.block) @scope.block
|
||||
|
||||
(table_constructor
|
||||
"{" @open.table
|
||||
"}" @close.table) @scope.table
|
||||
|
||||
(function_call
|
||||
(arguments
|
||||
"(" @open.call
|
||||
")" @close.call)) @scope.call
|
||||
|
||||
@@ -1,40 +1,87 @@
|
||||
(for "for" @open.loop "in" @mid.loop.3) @scope.loop
|
||||
(while "while" @open.loop) @scope.loop
|
||||
(block "block" @open.loop) @scope.loop
|
||||
(break_statement "break" @mid.loop.1)
|
||||
(continue_statement "continue" @mid.loop.2)
|
||||
(for
|
||||
"for" @open.loop
|
||||
"in" @mid.loop.3) @scope.loop
|
||||
|
||||
(if "if" @open.conditional) @scope.conditional
|
||||
(when "when" @open.conditional) @scope.conditional
|
||||
(elif_branch "elif" @mid.conditional.1)
|
||||
(else_branch "else" @mid.conditional.2)
|
||||
(while
|
||||
"while" @open.loop) @scope.loop
|
||||
|
||||
(case "case" @open.conditional) @scope.conditional
|
||||
(of_branch "of" @mid.conditional.3)
|
||||
(block
|
||||
"block" @open.loop) @scope.loop
|
||||
|
||||
(variant_declaration "case" @open.conditional) @scope.conditional
|
||||
(conditional_declaration "when" @open.conditional) @scope.conditional
|
||||
(break_statement
|
||||
"break" @mid.loop.1)
|
||||
|
||||
(try "try" @open.try) @scope.try
|
||||
(except_branch "except" @mid.try.1 )
|
||||
(finally_branch "finally" @mid.try.2)
|
||||
(continue_statement
|
||||
"continue" @mid.loop.2)
|
||||
|
||||
(proc_declaration "proc" @open.routine) @scope.routine
|
||||
(func_declaration "func" @open.routine) @scope.routine
|
||||
(method_declaration "method" @open.routine) @scope.routine
|
||||
(converter_declaration "converter" @open.routine) @scope.routine
|
||||
(template_declaration "template" @open.routine) @scope.routine
|
||||
(macro_declaration "macro" @open.routine) @scope.routine
|
||||
(if
|
||||
"if" @open.conditional) @scope.conditional
|
||||
|
||||
(proc_expression "proc" @open.routine) @scope.routine
|
||||
(func_expression "func" @open.routine) @scope.routine
|
||||
(when
|
||||
"when" @open.conditional) @scope.conditional
|
||||
|
||||
(return_statement "return" @mid.routine.1)
|
||||
(elif_branch
|
||||
"elif" @mid.conditional.1)
|
||||
|
||||
(iterator_declaration "iterator" @open.iterator) @scope.iterator
|
||||
(iterator_expression "iterator" @open.iterator) @scope.iterator
|
||||
(else_branch
|
||||
"else" @mid.conditional.2)
|
||||
|
||||
(yield_statement "yield" @mid.iterator.1)
|
||||
(case
|
||||
"case" @open.conditional) @scope.conditional
|
||||
|
||||
(of_branch
|
||||
"of" @mid.conditional.3)
|
||||
|
||||
(variant_declaration
|
||||
"case" @open.conditional) @scope.conditional
|
||||
|
||||
(conditional_declaration
|
||||
"when" @open.conditional) @scope.conditional
|
||||
|
||||
(try
|
||||
"try" @open.try) @scope.try
|
||||
|
||||
(except_branch
|
||||
"except" @mid.try.1)
|
||||
|
||||
(finally_branch
|
||||
"finally" @mid.try.2)
|
||||
|
||||
(proc_declaration
|
||||
"proc" @open.routine) @scope.routine
|
||||
|
||||
(func_declaration
|
||||
"func" @open.routine) @scope.routine
|
||||
|
||||
(method_declaration
|
||||
"method" @open.routine) @scope.routine
|
||||
|
||||
(converter_declaration
|
||||
"converter" @open.routine) @scope.routine
|
||||
|
||||
(template_declaration
|
||||
"template" @open.routine) @scope.routine
|
||||
|
||||
(macro_declaration
|
||||
"macro" @open.routine) @scope.routine
|
||||
|
||||
(proc_expression
|
||||
"proc" @open.routine) @scope.routine
|
||||
|
||||
(func_expression
|
||||
"func" @open.routine) @scope.routine
|
||||
|
||||
(return_statement
|
||||
"return" @mid.routine.1)
|
||||
|
||||
(iterator_declaration
|
||||
"iterator" @open.iterator) @scope.iterator
|
||||
|
||||
(iterator_expression
|
||||
"iterator" @open.iterator) @scope.iterator
|
||||
|
||||
(yield_statement
|
||||
"yield" @mid.iterator.1)
|
||||
|
||||
(import_statement
|
||||
"import" @open.import
|
||||
@@ -46,38 +93,63 @@
|
||||
"import" @mid.from.1) @scope.from
|
||||
|
||||
(char_literal
|
||||
. "'" @open.char
|
||||
.
|
||||
"'" @open.char
|
||||
"'" @close.char .) @scope.char
|
||||
|
||||
(interpreted_string_literal
|
||||
. "\"" @open.string
|
||||
.
|
||||
"\"" @open.string
|
||||
"\"" @close.string .) @scope.string
|
||||
|
||||
(raw_string_literal
|
||||
. ["r\"" "R\""] @open.string
|
||||
.
|
||||
[
|
||||
"r\""
|
||||
"R\""
|
||||
] @open.string
|
||||
"\"" @close.string .) @scope.string
|
||||
|
||||
(long_string_literal
|
||||
. ["\"\"\"" "r\"\"\"" "R\"\"\""] @open.multistring
|
||||
.
|
||||
[
|
||||
"\"\"\""
|
||||
"r\"\"\""
|
||||
"R\"\"\""
|
||||
] @open.multistring
|
||||
"\"\"\"" @close.multistring .) @scope.multistring
|
||||
|
||||
(generalized_string
|
||||
function: (_)
|
||||
. ["\"" "\"\"\""] @open.multistring
|
||||
["\"" "\"\"\""] @close.multistring .) @scope.multistring
|
||||
.
|
||||
[
|
||||
"\""
|
||||
"\"\"\""
|
||||
] @open.multistring
|
||||
[
|
||||
"\""
|
||||
"\"\"\""
|
||||
] @close.multistring .) @scope.multistring
|
||||
|
||||
(accent_quoted
|
||||
. "`" @open.accent
|
||||
.
|
||||
"`" @open.accent
|
||||
"`" @close.accent .) @scope.accent
|
||||
|
||||
(block_documentation_comment
|
||||
. "##[" @open.doc_comment
|
||||
.
|
||||
"##[" @open.doc_comment
|
||||
"]##" @close.doc_comment .) @scope.doc_comment
|
||||
|
||||
(block_comment
|
||||
. "#[" @open.comment
|
||||
.
|
||||
"#[" @open.comment
|
||||
"]#" @close.comment .) @scope.comment
|
||||
|
||||
(pragma_list
|
||||
. "{." @open.pragma
|
||||
["}" ".}"] @close.pragma .) @scope.pragma
|
||||
.
|
||||
"{." @open.pragma
|
||||
[
|
||||
"}"
|
||||
".}"
|
||||
] @close.pragma .) @scope.pragma
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
; --------------- let/in ---------------
|
||||
(let_expression
|
||||
"let" @open.let (binding_set)
|
||||
"in" @mid.let.1 (_)) @scope.let
|
||||
"let" @open.let
|
||||
(binding_set)
|
||||
"in" @mid.let.1
|
||||
(_)) @scope.let
|
||||
|
||||
; --------------- binding --------------
|
||||
; (binding (_)+ (function_exppression) ";") tend to be many lines long
|
||||
(binding
|
||||
(attrpath) @open.binding (function_expression)
|
||||
(attrpath) @open.binding
|
||||
(function_expression)
|
||||
";" @close.binding) @scope.binding
|
||||
|
||||
@@ -1,34 +1,54 @@
|
||||
; matches any conditional -> else type block -> end of final block
|
||||
(conditional_statement
|
||||
["if" "unless"] @open.if
|
||||
"elsif"? @mid.if.1
|
||||
"else"? @mid.if.2
|
||||
(block "}" @close.if) .
|
||||
) @scope.if
|
||||
[
|
||||
"if"
|
||||
"unless"
|
||||
] @open.if
|
||||
"elsif"? @mid.if.1
|
||||
"else"? @mid.if.2
|
||||
(block
|
||||
"}" @close.if) .) @scope.if
|
||||
|
||||
; matches any loop construct -> loop control (last, next) -> end of final block
|
||||
(_
|
||||
["for" "foreach" "while" "unless"] @open.loop
|
||||
(block "}" @close.loop) .
|
||||
) @scope.loop
|
||||
[
|
||||
"for"
|
||||
"foreach"
|
||||
"while"
|
||||
"unless"
|
||||
] @open.loop
|
||||
(block
|
||||
"}" @close.loop) .) @scope.loop
|
||||
|
||||
(loopex_expression) @mid.loop.1
|
||||
|
||||
; matches sub -> return -> end of block
|
||||
(_
|
||||
"sub" @open.fun
|
||||
(block "}" @close.fun) .
|
||||
) @scope.fun
|
||||
(return_expression "return" @mid.fun.1)
|
||||
"sub" @open.fun
|
||||
(block
|
||||
"}" @close.fun) .) @scope.fun
|
||||
|
||||
(return_expression
|
||||
"return" @mid.fun.1)
|
||||
|
||||
; handling for all the different quote types; multi part quotes cycle through
|
||||
[
|
||||
(_ "'" @open.quotelike (string_content) "'" @close.quotelike)
|
||||
(quoted_regexp "'" @open.quotelike "'" @close.quotelike)
|
||||
(_ "'" @open.quotelike (_) "'"+ @mid.quotelike.1 (replacement) "'" @close.quotelike)
|
||||
(_
|
||||
"'" @open.quotelike
|
||||
(string_content)
|
||||
"'" @close.quotelike)
|
||||
(quoted_regexp
|
||||
"'" @open.quotelike
|
||||
"'" @close.quotelike)
|
||||
(_
|
||||
"'" @open.quotelike
|
||||
(_)
|
||||
"'"+ @mid.quotelike.1
|
||||
(replacement)
|
||||
"'" @close.quotelike)
|
||||
] @scope.quotelike
|
||||
|
||||
(try_statement
|
||||
"try" @open.try
|
||||
"catch"? @mid.try.1
|
||||
"finally"? @close.try
|
||||
) @scope.try
|
||||
"finally"? @close.try) @scope.try
|
||||
|
||||
@@ -1,31 +1,43 @@
|
||||
(if_statement
|
||||
"if" @open.if
|
||||
alternative: (elif_clause "elif" @mid.if.1)?
|
||||
alternative: (else_clause "else" @mid.if.2)?) @scope.if
|
||||
alternative: (elif_clause
|
||||
"elif" @mid.if.1)?
|
||||
alternative: (else_clause
|
||||
"else" @mid.if.2)?) @scope.if
|
||||
|
||||
(function_definition
|
||||
"def" @open.function) @scope.function
|
||||
|
||||
(return_statement
|
||||
"return" @mid.function.1)
|
||||
|
||||
(yield
|
||||
"yield" @mid.function.2)
|
||||
|
||||
(for_statement
|
||||
("for" @open.loop)
|
||||
alternative: (else_clause "else" @mid.loop.1)?) @scope.loop
|
||||
"for" @open.loop
|
||||
alternative: (else_clause
|
||||
"else" @mid.loop.1)?) @scope.loop
|
||||
|
||||
(while_statement
|
||||
("while" @open.loop)
|
||||
alternative: (else_clause "else" @mid.loop.1)?) @scope.loop
|
||||
"while" @open.loop
|
||||
alternative: (else_clause
|
||||
"else" @mid.loop.1)?) @scope.loop
|
||||
|
||||
(break_statement
|
||||
"break" @mid.loop.2)
|
||||
|
||||
(continue_statement
|
||||
"continue" @mid.loop.3)
|
||||
|
||||
(try_statement
|
||||
("try" @open.try)
|
||||
(finally_clause "finally" @mid.try.1)?
|
||||
(except_clause "except" @mid.try.2)?
|
||||
(else_clause "else" @mid.try.3)?) @scope.try
|
||||
"try" @open.try
|
||||
(finally_clause
|
||||
"finally" @mid.try.1)?
|
||||
(except_clause
|
||||
"except" @mid.try.2)?
|
||||
(else_clause
|
||||
"else" @mid.try.3)?) @scope.try
|
||||
|
||||
(string
|
||||
(string_start) @open.quote_all
|
||||
|
||||
@@ -1,49 +1,65 @@
|
||||
(method
|
||||
"def" @open.def
|
||||
"end" @close.def) @scope.def
|
||||
|
||||
(singleton_method
|
||||
"def" @open.def
|
||||
"end" @close.def) @scope.def
|
||||
|
||||
(return
|
||||
"return" @mid.def.1)
|
||||
|
||||
(yield
|
||||
"yield" @mid.def.2)
|
||||
|
||||
(body_statement
|
||||
(rescue "rescue" @mid.def.1))
|
||||
(rescue
|
||||
"rescue" @mid.def.1))
|
||||
|
||||
(body_statement
|
||||
(ensure "ensure" @mid.def.2))
|
||||
(ensure
|
||||
"ensure" @mid.def.2))
|
||||
|
||||
(class
|
||||
"class" @open.class
|
||||
"end" @close.class) @scope.class
|
||||
|
||||
(singleton_class
|
||||
"class" @open.class
|
||||
"end" @close.class) @scope.class
|
||||
|
||||
(if
|
||||
"if" @open.if
|
||||
(else "else" @mid.if.2)?
|
||||
(else
|
||||
"else" @mid.if.2)?
|
||||
"end" @close.if) @scope.if
|
||||
(elsif (else "else" @mid.if.2))
|
||||
(elsif "elsif" @mid.if.1)
|
||||
|
||||
(elsif
|
||||
(else
|
||||
"else" @mid.if.2))
|
||||
|
||||
(elsif
|
||||
"elsif" @mid.if.1)
|
||||
|
||||
(unless
|
||||
"unless" @open.unless
|
||||
(else "else" @mid.unless.2)?
|
||||
(else
|
||||
"else" @mid.unless.2)?
|
||||
"end" @close.unless) @scope.unless
|
||||
|
||||
(while
|
||||
"while" @open.loop
|
||||
"while" @open.loop
|
||||
body: (do
|
||||
"end" @close.loop)) @scope.loop
|
||||
|
||||
(for
|
||||
"for" @open.loop
|
||||
"for" @open.loop
|
||||
body: (do
|
||||
"end" @close.loop)) @scope.loop
|
||||
|
||||
(next
|
||||
"next" @mid.loop.1)?
|
||||
|
||||
(break
|
||||
"break" @mid.loop.2)?
|
||||
|
||||
@@ -72,12 +88,14 @@
|
||||
"end" @close.do) @scope.do
|
||||
|
||||
(if_modifier) @skip
|
||||
|
||||
(unless_modifier) @skip
|
||||
|
||||
(while_modifier) @skip
|
||||
|
||||
(until_modifier) @skip
|
||||
|
||||
(block_parameters
|
||||
("|") @open.block_param
|
||||
"|" @open.block_param
|
||||
(_)
|
||||
("|") @close.block_param
|
||||
) @scope.block_param
|
||||
"|" @close.block_param) @scope.block_param
|
||||
|
||||
@@ -10,24 +10,44 @@
|
||||
">" @open.typeparams) @scope.typeparams
|
||||
|
||||
; --------------- if/else ---------------
|
||||
(block (if_expression "if" @open.if_) @scope.if_)
|
||||
(expression_statement (if_expression "if" @open.if_) @scope.if_)
|
||||
(let_declaration (if_expression "if" @open.if_) @scope.if_)
|
||||
(block
|
||||
(if_expression
|
||||
"if" @open.if_) @scope.if_)
|
||||
|
||||
(expression_statement
|
||||
(if_expression
|
||||
"if" @open.if_) @scope.if_)
|
||||
|
||||
(let_declaration
|
||||
(if_expression
|
||||
"if" @open.if_) @scope.if_)
|
||||
|
||||
(else_clause "else" @mid.if_.1 (block))
|
||||
(else_clause
|
||||
"else" @_start (if_expression "if" @_end)
|
||||
(#make-range! "mid.if_.2" @_start @_end))
|
||||
"else" @mid.if_.1
|
||||
(block))
|
||||
|
||||
(else_clause
|
||||
"else" @mid.if_.2
|
||||
(if_expression
|
||||
"if" @mid.if_.2))
|
||||
|
||||
; --------------- async/await ---------------
|
||||
(function_item (function_modifiers "async" @open.async)) @scope.async
|
||||
(async_block "async" @open.async) @scope.async
|
||||
(await_expression "await" @mid.async.1)
|
||||
(function_item
|
||||
(function_modifiers
|
||||
"async" @open.async)) @scope.async
|
||||
|
||||
(async_block
|
||||
"async" @open.async) @scope.async
|
||||
|
||||
(await_expression
|
||||
"await" @mid.async.1)
|
||||
|
||||
; --------------- fn/return ---------------
|
||||
(function_item
|
||||
"fn" @open.function) @scope.function
|
||||
|
||||
(closure_expression) @scope.function
|
||||
|
||||
(return_expression
|
||||
"return" @mid.function.1)
|
||||
|
||||
@@ -37,10 +57,23 @@
|
||||
"|" @close.closureparams) @scope.closureparams
|
||||
|
||||
; --------------- while/loop/for + break/continue ---------------
|
||||
(for_expression . "for" @open.loop) @scope.loop
|
||||
(while_expression . "while" @open.loop) @scope.loop
|
||||
(loop_expression . "loop" @open.loop) @scope.loop
|
||||
(for_expression
|
||||
.
|
||||
"for" @open.loop) @scope.loop
|
||||
|
||||
(break_expression "break" @mid.loop.1 .)
|
||||
(break_expression "break" @mid.loop.1 .)
|
||||
(continue_expression "continue" @mid.loop.1 .)
|
||||
(while_expression
|
||||
.
|
||||
"while" @open.loop) @scope.loop
|
||||
|
||||
(loop_expression
|
||||
.
|
||||
"loop" @open.loop) @scope.loop
|
||||
|
||||
(break_expression
|
||||
"break" @mid.loop.1 .)
|
||||
|
||||
(break_expression
|
||||
"break" @mid.loop.1 .)
|
||||
|
||||
(continue_expression
|
||||
"continue" @mid.loop.1 .)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
; inherits: quote
|
||||
|
||||
(method_definition
|
||||
(method_definition
|
||||
".method" @open.function
|
||||
".end method" @close.function) @scope.function
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
; inherits: quote
|
||||
|
||||
[
|
||||
(element)
|
||||
(script_element)
|
||||
(style_element)
|
||||
(element)
|
||||
(script_element)
|
||||
(style_element)
|
||||
] @scope.tag
|
||||
|
||||
(start_tag (tag_name) @open.tag)
|
||||
(start_tag
|
||||
(tag_name) @open.tag)
|
||||
|
||||
(end_tag
|
||||
(tag_name) @close.tag
|
||||
@@ -17,7 +18,6 @@
|
||||
"/>" @close.selftag) @scope.selftag
|
||||
|
||||
; await
|
||||
|
||||
(await_statement
|
||||
(await_start
|
||||
(block_start_tag
|
||||
@@ -36,7 +36,6 @@
|
||||
(#offset! @mid.await.2 0 -1 0 0))
|
||||
|
||||
; each
|
||||
|
||||
(each_statement
|
||||
(each_start
|
||||
(block_start_tag
|
||||
@@ -49,7 +48,6 @@
|
||||
(#offset! @close.each 0 -1 0 0)))
|
||||
|
||||
; if
|
||||
|
||||
(if_statement
|
||||
(if_start
|
||||
(block_start_tag
|
||||
@@ -72,7 +70,6 @@
|
||||
(#offset! @close.if 0 -1 0 0)))
|
||||
|
||||
; key
|
||||
|
||||
(key_statement
|
||||
(key_start
|
||||
(block_start_tag
|
||||
@@ -85,7 +82,6 @@
|
||||
(#offset! @close.key 0 -1 0 0)))
|
||||
|
||||
; snippet
|
||||
|
||||
(snippet_statement
|
||||
(snippet_start
|
||||
(block_start_tag
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
; inherits: quote
|
||||
|
||||
[
|
||||
(component_if_statement)
|
||||
(conditional_attribute_if_statement)
|
||||
(component_if_statement)
|
||||
(conditional_attribute_if_statement)
|
||||
] @scope.if
|
||||
|
||||
; 'else'
|
||||
("else" @mid.if.1)
|
||||
"else" @mid.if.1
|
||||
|
||||
; if
|
||||
("if" @open.if)
|
||||
"if" @open.if
|
||||
|
||||
; switch
|
||||
(component_switch_statement "switch" @open.switch
|
||||
(component_switch_expression_case "case" @mid.switch.1)
|
||||
(component_switch_default_case "default" @mid.switch.2)) @scope.switch
|
||||
(component_switch_statement
|
||||
"switch" @open.switch
|
||||
(component_switch_expression_case
|
||||
"case" @mid.switch.1)
|
||||
(component_switch_default_case
|
||||
"default" @mid.switch.2)) @scope.switch
|
||||
|
||||
[
|
||||
(element)
|
||||
(script_element)
|
||||
(element)
|
||||
(script_element)
|
||||
] @scope.tag
|
||||
|
||||
(tag_start (element_identifier) @open.tag)
|
||||
(tag_start
|
||||
(element_identifier) @open.tag)
|
||||
|
||||
(tag_end
|
||||
(element_identifier) @close.tag
|
||||
(#offset! @close.tag 0 -1 0 0))
|
||||
@@ -30,8 +35,7 @@
|
||||
(style_tag_start) @open.style
|
||||
(#offset! @open.style 0 1 0 -1)
|
||||
(style_tag_end) @close.style
|
||||
(#offset! @close.style 0 1 0 -1)
|
||||
) @scope.style
|
||||
(#offset! @close.style 0 1 0 -1)) @scope.style
|
||||
|
||||
(self_closing_tag
|
||||
(element_identifier) @open.selftag
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
; inherits: ecma
|
||||
|
||||
(type_arguments) @scope.typeargs
|
||||
(type_arguments) "<" @open.typeargs
|
||||
(type_arguments) ">" @close.typeargs
|
||||
(type_arguments
|
||||
"<" @open.typeargs
|
||||
">" @close.typeargs) @scope.typeargs
|
||||
|
||||
(type_parameters) @scope.typeparams
|
||||
(type_parameters) "<" @open.typeparams
|
||||
(type_parameters) ">" @close.typeparams
|
||||
(type_parameters
|
||||
"<" @open.typeparams
|
||||
">" @close.typeparams) @scope.typeparams
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
(function_definition
|
||||
"function" @open.function
|
||||
"endfunction" @close.function) @scope.function
|
||||
|
||||
(return_statement
|
||||
"return" @mid.function.1)
|
||||
|
||||
(if_statement
|
||||
"if" @open.if
|
||||
"endif" @close.if) @scope.if
|
||||
|
||||
(elseif_statement
|
||||
"elseif" @mid.if.1)
|
||||
|
||||
(else_statement
|
||||
"else" @mid.if.2)
|
||||
|
||||
(for_loop
|
||||
"for" @open.loop
|
||||
"endfor" @close.loop) @scope.loop
|
||||
|
||||
(while_loop
|
||||
"while" @open.loop
|
||||
"endwhile" @close.loop) @scope.loop
|
||||
(continue_statement "continue" @mid.loop.1)
|
||||
(break_statement "break" @mid.loop.2)
|
||||
|
||||
(continue_statement
|
||||
"continue" @mid.loop.1)
|
||||
|
||||
(break_statement
|
||||
"break" @mid.loop.2)
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
; inherits: quote
|
||||
|
||||
[
|
||||
(element)
|
||||
(script_element)
|
||||
(style_element)
|
||||
(template_element)
|
||||
(element)
|
||||
(script_element)
|
||||
(style_element)
|
||||
(template_element)
|
||||
] @scope.tag
|
||||
|
||||
(start_tag (tag_name) @open.tag)
|
||||
(start_tag
|
||||
(tag_name) @open.tag)
|
||||
|
||||
(end_tag
|
||||
(tag_name) @close.tag
|
||||
(#offset! @close.tag 0 -1 0 0))
|
||||
|
||||
@@ -2,20 +2,27 @@
|
||||
|
||||
(function_declaration
|
||||
"fn" @open.function) @scope.function
|
||||
|
||||
(return_expression
|
||||
"return" @mid.function.1)
|
||||
|
||||
; 'else' and 'else if'
|
||||
(else_clause
|
||||
"else" @_start (if_statement "if" @_end)?
|
||||
(#make-range! "mid.if.1" @_start @_end))
|
||||
"else" @mid.if.1
|
||||
(if_statement
|
||||
"if" @mid.if.1)?)
|
||||
|
||||
; if
|
||||
((if_statement
|
||||
"if" @open.if) @scope.if
|
||||
(#not-has-parent? @scope.if else_clause))
|
||||
(#not-has-parent? @scope.if else_clause))
|
||||
|
||||
; Loops
|
||||
(while_statement "while" @open.loop) @scope.loop
|
||||
(break_expression "break" @mid.loop.1)
|
||||
(continue_expression "continue" @mid.loop.2)
|
||||
(while_statement
|
||||
"while" @open.loop) @scope.loop
|
||||
|
||||
(break_expression
|
||||
"break" @mid.loop.1)
|
||||
|
||||
(continue_expression
|
||||
"continue" @mid.loop.2)
|
||||
|
||||
@@ -76,6 +76,13 @@ function! s:init_options()
|
||||
call s:init_option('matchup_where_separator', '')
|
||||
|
||||
call s:init_option('matchup_matchpref', {})
|
||||
|
||||
call s:init_option('matchup_treesitter_enabled', has('nvim') ? v:true : v:false)
|
||||
call s:init_option('matchup_treesitter_disabled', {})
|
||||
call s:init_option('matchup_treesitter_include_match_words', v:false)
|
||||
call s:init_option('matchup_treesitter_enable_quotes', v:true)
|
||||
call s:init_option('matchup_treesitter_disable_virtual_text', v:true)
|
||||
call s:init_option('matchup_treesitter_stopline', 400)
|
||||
endfunction
|
||||
|
||||
function! s:init_option(option, default)
|
||||
@@ -408,17 +415,7 @@ function! s:treesitter_init_module() " {{{1
|
||||
if !matchup#loader#_treesitter_may_be_supported()
|
||||
return
|
||||
endif
|
||||
|
||||
lua require'treesitter-matchup'.init()
|
||||
|
||||
augroup matchup_filetype_query
|
||||
au!
|
||||
autocmd FileType query
|
||||
\ augroup MatchupTreesitter|augroup END
|
||||
\|autocmd! MatchupTreesitter BufWritePost <buffer>
|
||||
\ call v:lua.require('treesitter-matchup.third-party.query')
|
||||
\.invalidate_query_file(expand('%:p'))
|
||||
augroup END
|
||||
" TODO: do something?
|
||||
endfunction
|
||||
|
||||
"}}}1
|
||||
|
||||
@@ -25,30 +25,13 @@ function! matchup#loader#init_buffer() abort " {{{1
|
||||
let [l:no_words, l:filt_words] = [0, 0]
|
||||
if s:ts_may_be_supported && matchup#ts_engine#is_enabled(bufnr('%'))
|
||||
let l:has_ts = 1
|
||||
if matchup#ts_engine#get_option(bufnr('%'), 'include_match_words')
|
||||
if g:matchup_treesitter_include_match_words
|
||||
let l:filt_words = 1
|
||||
else
|
||||
let l:no_words = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
let l:has_ts_hl = 0
|
||||
if s:ts_may_be_supported && matchup#ts_engine#is_hl_enabled(bufnr('%'))
|
||||
let l:has_ts_hl = 1
|
||||
|
||||
if matchup#ts_engine#get_option(
|
||||
\ bufnr('%'), 'additional_vim_regex_highlighting')
|
||||
if empty(&syntax)
|
||||
set syntax=ON
|
||||
else
|
||||
augroup matchup_syntax
|
||||
au!
|
||||
autocmd VimEnter * if empty(&syntax) | set syntax=ON | endif
|
||||
augroup END
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
" initialize lists of delimiter pairs and regular expressions
|
||||
" this is the data obtained from parsing b:match_words
|
||||
let b:matchup_delim_lists = s:init_delim_lists(l:no_words, l:filt_words)
|
||||
@@ -58,7 +41,7 @@ function! matchup#loader#init_buffer() abort " {{{1
|
||||
let b:matchup_delim_re = s:init_delim_regexes()
|
||||
|
||||
" process b:match_skip
|
||||
if l:has_ts_hl
|
||||
if l:has_ts
|
||||
let b:matchup_delim_skip
|
||||
\ = "matchup#ts_syntax#skip_expr(s:effline('.'),s:effcol('.'))"
|
||||
else
|
||||
@@ -93,7 +76,7 @@ function! matchup#loader#_treesitter_may_be_supported() abort
|
||||
endfunction
|
||||
|
||||
let s:ts_may_be_supported = has('nvim-0.5.0') && exists('*luaeval')
|
||||
\ && luaeval('pcall(require, "treesitter-matchup")')
|
||||
\ && luaeval('pcall(require, "treesitter-matchup.internal")')
|
||||
|
||||
" }}}1
|
||||
function! matchup#loader#bufwinenter() abort " {{{1
|
||||
|
||||
@@ -1204,8 +1204,7 @@ function! s:add_matches(corrlist, ...) " {{{1
|
||||
if exists('s:ns_id')
|
||||
if strlen(l:corr.match) == 0
|
||||
\ && matchup#loader#_treesitter_may_be_supported()
|
||||
\ && !matchup#ts_engine#get_option(
|
||||
\ bufnr('%'), 'disable_virtual_text')
|
||||
\ && !g:matchup_treesitter_disable_virtual_text
|
||||
if hlexists('MatchupVirtualText')
|
||||
let l:group = 'MatchupVirtualText'
|
||||
endif
|
||||
|
||||
@@ -15,33 +15,12 @@ function! s:forward(fn, ...)
|
||||
endfunction
|
||||
|
||||
function! matchup#ts_engine#is_enabled(bufnr) abort
|
||||
if !has('nvim-0.5.0')
|
||||
if !has('nvim-0.9.0')
|
||||
return 0
|
||||
endif
|
||||
return +s:forward('is_enabled', a:bufnr)
|
||||
endfunction
|
||||
|
||||
function! matchup#ts_engine#is_hl_enabled(bufnr) abort
|
||||
if !has('nvim-0.5.0')
|
||||
return 0
|
||||
endif
|
||||
return +s:forward('is_hl_enabled', a:bufnr)
|
||||
endfunction
|
||||
|
||||
function! matchup#ts_engine#get_option(bufnr, opt_name) abort
|
||||
return s:forward('get_option', a:bufnr, a:opt_name)
|
||||
endfunction
|
||||
|
||||
let s:attached = {}
|
||||
|
||||
function! matchup#ts_engine#attach(bufnr, lang) abort
|
||||
let s:attached[a:bufnr] = a:lang
|
||||
endfunction
|
||||
|
||||
function! matchup#ts_engine#detach(bufnr) abort
|
||||
unlet s:attached[a:bufnr]
|
||||
endfunction
|
||||
|
||||
function! matchup#ts_engine#get_delim(opts) abort
|
||||
call matchup#perf#tic('ts_engine.get_delim')
|
||||
|
||||
|
||||
114
doc/matchup.txt
114
doc/matchup.txt
@@ -272,35 +272,21 @@ important special cases.
|
||||
|
||||
*matchup-treesitter*
|
||||
Tree-sitter integration~
|
||||
Note: Currently this feature is possible in neovim only. Only the latest
|
||||
version of neovim and nvim-treesitter is supported.
|
||||
Note: Currently this feature is possible in Neovim only. Only the latest
|
||||
stable version of Neovim is supported.
|
||||
|
||||
match-up has support for language syntax provided by tree-sitter. The list
|
||||
of supported languages is available here. This feature requires manual
|
||||
opt-in in your init.vim and requires nvim-treesitter to be installed. >
|
||||
of supported languages is available here.
|
||||
|
||||
Plug 'nvim-treesitter/nvim-treesitter'
|
||||
lua <<EOF
|
||||
require'nvim-treesitter.configs'.setup {
|
||||
matchup = {
|
||||
enable = true, -- mandatory, false will disable the whole extension
|
||||
disable = { "c", "ruby" }, -- optional, list of language that will be disabled
|
||||
-- [options]
|
||||
},
|
||||
}
|
||||
<
|
||||
Beside enable and disable, the following options are available, all
|
||||
defaulting to false:
|
||||
|
||||
*disable_virtual_text*
|
||||
This feature is automatically enabled if you are using Neovim. And does not
|
||||
require other plugins to work.
|
||||
|
||||
If true, do not use virtual text to highlight the virtual end of a
|
||||
block, for languages without explicit end markers (e.g., Python).
|
||||
|
||||
*include_match_words*
|
||||
|
||||
If true, additionally include traditional vim regex matches for symbols.
|
||||
The treesitter related configuration options share the prefix
|
||||
`g:matchup_treesitter`. You can check them on `:h g:matchup_treesitter_enabled`
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Highlighting matches~
|
||||
|
||||
To disable match highlighting at |startup|, use >
|
||||
@@ -542,7 +528,7 @@ Options~
|
||||
*g:matchup_delim_nomids*
|
||||
|
||||
If set to 1, middle words (like `return`) are not matched to start and
|
||||
end words for higlighting and motions.
|
||||
end words for higlighting and motions. >
|
||||
|
||||
let g:matchup_delim_noskips = 0
|
||||
<
|
||||
@@ -552,10 +538,82 @@ Options~
|
||||
|
||||
When enabled (the default), the plugin will be loaded for all buffers,
|
||||
including ones without a file type set. This allows matching to be done in
|
||||
new buffers and plain text files but adds a small start-up cost to vim.
|
||||
new buffers and plain text files but adds a small start-up cost to vim. >
|
||||
|
||||
let g:matchup_delim_start_plaintext = 0
|
||||
<
|
||||
|
||||
Default: 1
|
||||
|
||||
*g:matchup_treesitter_enabled*
|
||||
|
||||
When enabled (the default on Neovim), the plugin will use the builtin
|
||||
|treesitter| interface to compute matches. >
|
||||
|
||||
let g:matchup_treesitter_enabled = v:true
|
||||
<
|
||||
|
||||
Default: v:true
|
||||
|
||||
Note: expects either |v:true| or |v:false|.
|
||||
|
||||
*g:matchup_treesitter_disabled*
|
||||
|
||||
List of treesitter languages (not filetypes, see |treesitter-language|) for
|
||||
which the treesitter engine will be disabled >
|
||||
|
||||
let g:matchup_treesitter_disabled = []
|
||||
<
|
||||
|
||||
Default: []
|
||||
|
||||
*g:matchup_treesitter_include_match_words*
|
||||
|
||||
Additionally include traditional vim regex matches for symbols. For example,
|
||||
highlights `/* */` comments in C++ which are not supported in tree-sitter
|
||||
matching. >
|
||||
|
||||
let g:matchup_treesitter_include_match_words = v:false
|
||||
<
|
||||
|
||||
Default: v:false
|
||||
|
||||
Note: expects either |v:true| or |v:false|.
|
||||
|
||||
*g:matchup_treesitter_disable_virtual_text*
|
||||
|
||||
Do not use virtual text to highlight the virtual end of a block, for
|
||||
languages without explicit end markers (e.g., Python). >
|
||||
|
||||
let g:matchup_treesitter_disable_virtual_text = v:true
|
||||
<
|
||||
|
||||
Default: v:true
|
||||
|
||||
Note: expects either |v:true| or |v:false|.
|
||||
|
||||
*g:matchup_treesitter_enable_quotes*
|
||||
|
||||
Include quotes as possible matches. >
|
||||
|
||||
let g:matchup_treesitter_enable_quotes = v:true
|
||||
<
|
||||
|
||||
Default: v:true
|
||||
|
||||
Note: expects either |v:true| or |v:false|.
|
||||
|
||||
*g:matchup_treesitter_stopline*
|
||||
|
||||
The number of lines to parse using treesitter in either direction while
|
||||
highlighting matches, using motions and textobjects. Set this
|
||||
conservatively since high values may cause performance issues. >
|
||||
|
||||
let g:matchup_treesitter_stopline = 400
|
||||
<
|
||||
|
||||
Default: 400
|
||||
|
||||
Variables~
|
||||
|
||||
*b:match_words*
|
||||
@@ -666,7 +724,7 @@ Module matchparen~
|
||||
`MatchupStatusOffscreen()` can be used to get the text.
|
||||
|
||||
`'popup'`: Use a popup window (requires at least vim 8.1.1406) or
|
||||
a floating window (in neovim) to show the off-screen match.
|
||||
a floating window (in Neovim) to show the off-screen match.
|
||||
|
||||
scrolloff~
|
||||
When enabled, off-screen matches will not be shown in the statusline while
|
||||
@@ -696,7 +754,7 @@ Module matchparen~
|
||||
Default: 0
|
||||
|
||||
border~
|
||||
For floating window on neovim only: set to add a border. If the value
|
||||
For floating window on Neovim only: set to add a border. If the value
|
||||
is the integer 1, default borders are enabled. A list or string can
|
||||
be specified as described in |nvim_open_win()|.
|
||||
|
||||
@@ -822,7 +880,7 @@ the function |timer_pause|, version 7.4.2180 and after.
|
||||
|
||||
*g:matchup_matchparen_end_sign*
|
||||
|
||||
(neovim only) Configure the virtual symbol shown for closeless matches in languages like
|
||||
(Neovim only) Configure the virtual symbol shown for closeless matches in languages like
|
||||
C++ and python.
|
||||
|
||||
if (true)
|
||||
@@ -834,7 +892,7 @@ the function |timer_pause|, version 7.4.2180 and after.
|
||||
|
||||
*MatchupVirtualText*
|
||||
|
||||
(neovim only) You can also configure the color and style of the virtual text.
|
||||
(Neovim only) You can also configure the color and style of the virtual text.
|
||||
|
||||
:hi MatchupVirtualText ctermbg=blue guibg=lightblue gui=italic
|
||||
|
||||
|
||||
113
lua/match-up.lua
113
lua/match-up.lua
@@ -1,23 +1,124 @@
|
||||
local M = {}
|
||||
|
||||
---@class matchup.DelimConfig
|
||||
---@field count_fail 0|1
|
||||
---@field nomids 0|1
|
||||
---@field noskips 0|1|2
|
||||
---@field start_plaintext 0|1
|
||||
---@field stopline integer
|
||||
|
||||
---@class matchup.HotfixConfig
|
||||
---@field enabled 0|1
|
||||
|
||||
---@class matchup.MappingsConfig
|
||||
---@field enabled 0|1
|
||||
|
||||
---@class matchup.OffscreenConfig
|
||||
---@field method 'status'|'status_manual'|'popup'
|
||||
---@field scrolloff 0|1
|
||||
---@field fullwidth 0|1
|
||||
--@field highlight string Vim exclusive option. Intentionally excluded from type
|
||||
--@field syntax_hl 0|1 Vim exclusive option. Intentionally excluded from type
|
||||
---@field border 1|string|string[]
|
||||
|
||||
---@class matchup.MatchparenConfig
|
||||
---@field deferred 0|1
|
||||
---@field deferred_fade_time integer
|
||||
---@field deferred_hide_delay integer
|
||||
---@field deferred_show_delay integer
|
||||
---@field enabled 0|1
|
||||
---@field end_sign string
|
||||
---@field hi_background 0|1
|
||||
---@field hi_surround_always 0|1
|
||||
---@field insert_timeout integer
|
||||
---@field nomode string
|
||||
---@field offscreen matchup.OffscreenConfig
|
||||
---@field pumvisible 0|1
|
||||
---@field singleton 0|1
|
||||
---@field stopline integer
|
||||
---@field timeout integer
|
||||
|
||||
---@class matchup.MatchprefHtmlConfig
|
||||
---@field nolists 0|1
|
||||
---@field tagnameonly 0|1
|
||||
|
||||
---@class matchup.MatchprefConfig
|
||||
---@field html matchup.MatchprefHtmlConfig
|
||||
|
||||
---@class matchup.MotionConfig
|
||||
---@field cursor_end 0|1
|
||||
---@field enabled 0|1
|
||||
---@field override_Npercent integer
|
||||
|
||||
---@class matchup.MouseConfig
|
||||
---@field enabled 0|1
|
||||
|
||||
---@class matchup.OverrideConfig
|
||||
---@field vimtex 1|0
|
||||
|
||||
---@class matchup.SurroundConfig
|
||||
---@field enabled 0|1
|
||||
|
||||
---@class matchup.TextObjConfig
|
||||
---@field enabled 0|1
|
||||
---@field linewise_operators string[]
|
||||
|
||||
---@class matchup.TransmuteConfig
|
||||
---@field enabled 0|1
|
||||
|
||||
---@class matchup.TreesitterConfig
|
||||
---@field enabled boolean
|
||||
---@field disabled string[]
|
||||
---@field include_match_words boolean
|
||||
---@field disable_virtual_text boolean
|
||||
---@field enable_quotes boolean
|
||||
---@field stopline integer
|
||||
|
||||
---@class matchup.Config
|
||||
---@field delim matchup.DelimConfig
|
||||
---@field enabled 0|1
|
||||
---@field hotfix matchup.HotfixConfig
|
||||
---@field mappings matchup.MappingsConfig
|
||||
---@field matchparen matchup.MatchparenConfig
|
||||
---@field matchpref matchup.MatchprefConfig
|
||||
---@field motion matchup.MotionConfig
|
||||
---@field mouse matchup.MouseConfig
|
||||
---@field override matchup.OverrideConfig
|
||||
---@field surround matchup.SurroundConfig
|
||||
---@field text_obj matchup.TextObjConfig
|
||||
---@field transmute matchup.TransmuteConfig
|
||||
---@field treesitter matchup.TreesitterConfig
|
||||
|
||||
---@param opts matchup.Config
|
||||
---@param validate boolean
|
||||
local function do_setup(opts, validate)
|
||||
for mod, elem in pairs(opts) do
|
||||
for key, val in pairs(type(elem) == 'table' and elem or {}) do
|
||||
local opt = 'matchup_'..mod..'_'..key
|
||||
if validate and vim.g[opt] == nil then
|
||||
error(string.format('invalid option name %s.%s', mod, key))
|
||||
for mod, elem in pairs(opts --[[@as table<string, unknown|table<string, unknown>>]]) do
|
||||
if type(elem) == 'table' then
|
||||
for key, val in pairs(elem) do
|
||||
local opt = 'matchup_'..mod..'_'..key
|
||||
if validate and vim.g[opt] == nil then
|
||||
error(('invalid option name %s.%s'):format(mod, key))
|
||||
end
|
||||
vim.g[opt] = val
|
||||
end
|
||||
vim.g[opt] = val
|
||||
else
|
||||
if validate and vim.g[mod] == nil then
|
||||
error(('invalid option name %s'):format(mod))
|
||||
end
|
||||
vim.g[mod] = elem
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param opts matchup.Config|{sync: boolean}
|
||||
function M.setup(opts)
|
||||
local sync = opts.sync
|
||||
if sync then
|
||||
vim.cmd[[runtime! plugin/matchup.vim]]
|
||||
end
|
||||
|
||||
opts.sync = nil
|
||||
---@cast opts matchup.Config
|
||||
do_setup(opts, sync)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
if not pcall(require, 'nvim-treesitter') then
|
||||
return {init = function() end}
|
||||
end
|
||||
|
||||
local treesitter = require 'nvim-treesitter'
|
||||
local queries = require 'nvim-treesitter.query'
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.init()
|
||||
treesitter.define_modules {
|
||||
matchup = {
|
||||
module_path = 'treesitter-matchup.internal',
|
||||
is_supported = function(lang)
|
||||
return queries.has_query_files(lang, 'matchup')
|
||||
end
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -1,18 +1,10 @@
|
||||
if not pcall(require, 'nvim-treesitter') then
|
||||
return {is_enabled = function(bufnr) return 0 end,
|
||||
is_hl_enabled = function(bufnr) return 0 end}
|
||||
end
|
||||
|
||||
local vim = vim
|
||||
local api = vim.api
|
||||
local ts = require'treesitter-matchup.compat'
|
||||
local configs = require'nvim-treesitter.configs'
|
||||
local parsers = require'nvim-treesitter.parsers'
|
||||
local queries = require'treesitter-matchup.third-party.query'
|
||||
local ts_utils = require'nvim-treesitter.ts_utils'
|
||||
local ts = vim.treesitter
|
||||
local memoize = require'treesitter-matchup.third-party.ts-utils'.memoize
|
||||
|
||||
local lru = require'treesitter-matchup.third-party.lru'
|
||||
local util = require'treesitter-matchup.util'
|
||||
local utils2 = require'treesitter-matchup.third-party.utils'
|
||||
|
||||
local unpack = unpack or table.unpack
|
||||
|
||||
@@ -20,69 +12,177 @@ local M = {}
|
||||
|
||||
local cache = lru.new(150)
|
||||
|
||||
|
||||
---@param lang string
|
||||
---@param bufnr integer
|
||||
local function is_enabled(lang, bufnr)
|
||||
local enabled = vim.g.matchup_treesitter_enabled
|
||||
local buf_enabled = vim.b[bufnr].matchup_treesitter_enabled
|
||||
local lang_disabled = vim.list_contains(vim.g.matchup_treesitter_disabled, lang)
|
||||
|
||||
if buf_enabled == false then
|
||||
return false
|
||||
end
|
||||
|
||||
return enabled and not lang_disabled
|
||||
end
|
||||
|
||||
---@param bufnr integer?
|
||||
---@return boolean
|
||||
function M.is_enabled(bufnr)
|
||||
bufnr = bufnr or api.nvim_get_current_buf()
|
||||
local lang = parsers.get_buf_lang(bufnr)
|
||||
return configs.is_enabled('matchup', lang, bufnr)
|
||||
if not api.nvim_buf_is_loaded(bufnr) then
|
||||
return false
|
||||
end
|
||||
local lang = ts.language.get_lang(vim.bo[bufnr].filetype)
|
||||
if not lang then
|
||||
return false
|
||||
end
|
||||
local _, err = ts.get_parser(bufnr, nil, {error = false})
|
||||
if err then
|
||||
return false
|
||||
end
|
||||
return is_enabled(lang, bufnr)
|
||||
end
|
||||
|
||||
function M.is_hl_enabled(bufnr)
|
||||
bufnr = bufnr or api.nvim_get_current_buf()
|
||||
local lang = parsers.get_buf_lang(bufnr)
|
||||
return configs.is_enabled('highlight', lang, bufnr)
|
||||
---@param bufnr integer
|
||||
---@param root TSNode
|
||||
---@param lang string
|
||||
---@return string
|
||||
local function buf_root_lang_hash(bufnr, root, lang)
|
||||
return tostring(bufnr) .. root:id() .. '_' .. lang
|
||||
end
|
||||
|
||||
M.get_matches = ts_utils.memoize_by_buf_tick(function(bufnr)
|
||||
local parser = parsers.get_parser(bufnr)
|
||||
local matches = {}
|
||||
---@class matchup.treesitter.MatchInfo
|
||||
---@field range Range4
|
||||
---@field length integer
|
||||
---@field last_node TSNode
|
||||
---@field text string
|
||||
|
||||
---@class matchup.treesitter.MatchInfoWrapper
|
||||
---@field info matchup.treesitter.MatchInfo
|
||||
|
||||
---@class matchup.treesitter.Match
|
||||
---@field scope? table<string, matchup.treesitter.MatchInfoWrapper>
|
||||
---@field open? table<string, matchup.treesitter.MatchInfoWrapper>
|
||||
---@field mid? table<string, table<string, matchup.treesitter.MatchInfoWrapper>>
|
||||
---@field close? table<string, matchup.treesitter.MatchInfoWrapper>
|
||||
---@field skip? matchup.treesitter.MatchInfoWrapper
|
||||
|
||||
---@param bufnr integer
|
||||
---@param root TSNode
|
||||
---@param lang string
|
||||
---@return matchup.treesitter.Match[]
|
||||
local get_memoized_matches = memoize(function(bufnr, root, lang)
|
||||
local query_name = 'matchup'
|
||||
local query = ts.query.get(lang, query_name)
|
||||
|
||||
if not query then
|
||||
return {}
|
||||
end
|
||||
|
||||
local out = {} ---@type matchup.treesitter.Match[]
|
||||
for _, match, metadata in query:iter_matches(root, bufnr) do
|
||||
local match_info = {}
|
||||
for id, nodes in pairs(match) do
|
||||
local first = nodes[1]
|
||||
local last = nodes[#nodes]
|
||||
|
||||
---@type integer, integer, integer
|
||||
local start_row, start_col , start_byte = unpack(ts.get_range(first, bufnr, metadata))
|
||||
---@type integer, integer, integer, integer, integer, integer
|
||||
local _, _, _, end_row, end_col , end_byte = unpack(ts.get_range(last, bufnr, metadata))
|
||||
local range = { start_row, start_col, end_row, end_col }
|
||||
local length = end_byte - start_byte
|
||||
|
||||
if end_col == 0 then
|
||||
if start_row == end_row then
|
||||
start_col = -1
|
||||
start_row = start_row - 1
|
||||
end
|
||||
end_col = -1
|
||||
end_row = end_row - 1
|
||||
end
|
||||
local lines = api.nvim_buf_get_text(bufnr, start_row, start_col, end_row, end_col, {})
|
||||
local text = table.concat(lines, '\n')
|
||||
|
||||
local name = query.captures[id]
|
||||
local path = vim.split(name, '.', { plain = true })
|
||||
|
||||
local current = match_info ---@type table<string, table<string, matchup.treesitter.MatchInfo>>
|
||||
for _, segment in ipairs(path) do
|
||||
current[segment] = current[segment] or {}
|
||||
current = current[segment]
|
||||
end
|
||||
current.info = {
|
||||
range = range,
|
||||
length = length,
|
||||
last_node = last,
|
||||
text = text,
|
||||
}
|
||||
end
|
||||
table.insert(out, match_info)
|
||||
end
|
||||
|
||||
return out
|
||||
end, buf_root_lang_hash)
|
||||
|
||||
---@param bufnr integer
|
||||
---@return matchup.treesitter.Match[]
|
||||
M.get_matches = function(bufnr)
|
||||
local parser = ts.get_parser(bufnr)
|
||||
local matches = {} ---@type matchup.treesitter.Match[]
|
||||
|
||||
if parser then
|
||||
-- NOTE: assummes that we are always parsing the current window. May cause
|
||||
-- issues if that's not always the case
|
||||
local win = api.nvim_get_current_win()
|
||||
local cur_row = unpack(api.nvim_win_get_cursor(win))
|
||||
local stopline = vim.g.matchup_treesitter_stopline ---@type integer
|
||||
local start_row = math.max(cur_row - stopline, 0)
|
||||
local end_row = math.min(cur_row + stopline, api.nvim_buf_line_count(bufnr))
|
||||
|
||||
parser:parse({start_row, end_row})
|
||||
parser:for_each_tree(function(tree, lang_tree)
|
||||
if not tree or lang_tree:lang() == 'comment' then
|
||||
return
|
||||
end
|
||||
|
||||
local lang = lang_tree:lang()
|
||||
local group_results = queries.collect_group_results(
|
||||
bufnr, 'matchup', tree:root(), lang) or {}
|
||||
local group_results = get_memoized_matches(bufnr, tree:root(), lang)
|
||||
vim.list_extend(matches, group_results)
|
||||
end)
|
||||
end
|
||||
|
||||
return matches
|
||||
end)
|
||||
end
|
||||
|
||||
local function _time()
|
||||
local s, u = vim.loop.gettimeofday()
|
||||
local s, u = vim.uv.gettimeofday()
|
||||
return s * 1000 + u * 1e-3
|
||||
end
|
||||
|
||||
--- Returns a (mostly) unique id for this node
|
||||
-- Also supports nvim-treesitter's range object
|
||||
local function _node_id(node)
|
||||
if not node then
|
||||
return nil
|
||||
end
|
||||
if node:type() == 'nvim-treesitter-range' then
|
||||
return string.format('range_%d_%d_%d_%d', node:range())
|
||||
end
|
||||
return node:id()
|
||||
--- Returns a (mostly) unique id for this range
|
||||
---@param range Range4
|
||||
---@return string
|
||||
function M.range_id(range)
|
||||
return ('range_%d_%d_%d_%d'):format(unpack(range))
|
||||
end
|
||||
|
||||
--- Get all nodes belonging to defined scopes (organized by key)
|
||||
M.get_scopes = ts_utils.memoize_by_buf_tick(function(bufnr)
|
||||
---@param bufnr integer
|
||||
---@return table<string, table<string, boolean>>
|
||||
M.get_scopes = function(bufnr)
|
||||
local matches = M.get_matches(bufnr)
|
||||
|
||||
local scopes = {}
|
||||
local scopes = {} ---@type table<string, table<string, boolean>>
|
||||
|
||||
for _, match in ipairs(matches) do
|
||||
if match.scope then
|
||||
for key, scope in pairs(match.scope) do
|
||||
local id = _node_id(scope.node)
|
||||
if scope.node then
|
||||
if not scopes[key] then
|
||||
scopes[key] = {}
|
||||
end
|
||||
if scope.info then
|
||||
local id = M.range_id(scope.info.range)
|
||||
scopes[key] = scopes[key] or {}
|
||||
scopes[key][id] = true
|
||||
end
|
||||
end
|
||||
@@ -90,39 +190,41 @@ M.get_scopes = ts_utils.memoize_by_buf_tick(function(bufnr)
|
||||
end
|
||||
|
||||
return scopes
|
||||
end)
|
||||
end
|
||||
|
||||
M.get_active_nodes = ts_utils.memoize_by_buf_tick(function(bufnr)
|
||||
-- TODO: why do we need to force a parse?
|
||||
if not pcall(function() parsers.get_parser():parse() end) then
|
||||
-- TODO workaround a crash due to tree-sitter parsing
|
||||
return {{ open={}, mid={}, close={} }, {}}
|
||||
end
|
||||
---@class matchup.treesitter.Matches
|
||||
---@field open matchup.treesitter.MatchInfo[]
|
||||
---@field mid matchup.treesitter.MatchInfo[]
|
||||
---@field close matchup.treesitter.MatchInfo[]
|
||||
|
||||
---@param bufnr integer
|
||||
---@return [matchup.treesitter.Matches, table<string, string>]
|
||||
M.get_active_matches = function(bufnr)
|
||||
local matches = M.get_matches(bufnr)
|
||||
|
||||
local nodes = { open = {}, mid = {}, close = {} }
|
||||
---@type matchup.treesitter.Matches
|
||||
local info = { open = {}, mid = {}, close = {} }
|
||||
---@type table<string, string>
|
||||
local symbols = {}
|
||||
|
||||
local enable_quotes = vim.g.matchup_treesitter_enable_quotes
|
||||
for _, match in ipairs(matches) do
|
||||
if match.open then
|
||||
for key, open in pairs(match.open) do
|
||||
local reject = key:find('quote')
|
||||
and not M.get_option(bufnr, 'enable_quotes')
|
||||
local id = _node_id(open.node)
|
||||
if not reject and open.node and symbols[id] == nil then
|
||||
table.insert(nodes.open, open.node)
|
||||
local reject = key:find('quote') and not enable_quotes
|
||||
local id = M.range_id(open.info.range)
|
||||
if not reject and open.info and symbols[id] == nil then
|
||||
table.insert(info.open, open.info)
|
||||
symbols[id] = key
|
||||
end
|
||||
end
|
||||
end
|
||||
if match.close then
|
||||
for key, close in pairs(match.close) do
|
||||
local reject = key:find('quote')
|
||||
and not M.get_option(bufnr, 'enable_quotes')
|
||||
local id = _node_id(close.node)
|
||||
if not reject and close.node and symbols[id] == nil then
|
||||
table.insert(nodes.close, close.node)
|
||||
local reject = key:find('quote') and not enable_quotes
|
||||
local id = M.range_id(close.info.range)
|
||||
if not reject and close.info and symbols[id] == nil then
|
||||
table.insert(info.close, close.info)
|
||||
symbols[id] = key
|
||||
end
|
||||
end
|
||||
@@ -130,9 +232,9 @@ M.get_active_nodes = ts_utils.memoize_by_buf_tick(function(bufnr)
|
||||
if match.mid then
|
||||
for key, mid_group in pairs(match.mid) do
|
||||
for _, mid in pairs(mid_group) do
|
||||
local id = _node_id(mid.node)
|
||||
if mid.node and symbols[id] == nil then
|
||||
table.insert(nodes.mid, mid.node)
|
||||
local id = M.range_id(mid.info.range)
|
||||
if mid.info and symbols[id] == nil then
|
||||
table.insert(info.mid, mid.info)
|
||||
symbols[id] = key
|
||||
end
|
||||
end
|
||||
@@ -140,19 +242,25 @@ M.get_active_nodes = ts_utils.memoize_by_buf_tick(function(bufnr)
|
||||
end
|
||||
end
|
||||
|
||||
return {nodes, symbols}
|
||||
end)
|
||||
return {info, symbols}
|
||||
end
|
||||
|
||||
function M.containing_scope(node, bufnr, key)
|
||||
---@param info matchup.treesitter.MatchInfo?
|
||||
---@param bufnr integer?
|
||||
---@param key string
|
||||
---@return TSNode|nil
|
||||
function M.containing_scope(info, bufnr, key)
|
||||
bufnr = bufnr or api.nvim_get_current_buf()
|
||||
|
||||
local scopes = M.get_scopes(bufnr)
|
||||
if not node or not scopes or not scopes[key] then return end
|
||||
if not info or not scopes or not scopes[key] then return end
|
||||
|
||||
local iter_node = node
|
||||
---@type TSNode|nil
|
||||
local iter_node = info.last_node
|
||||
|
||||
while iter_node ~= nil do
|
||||
if scopes[key][_node_id(iter_node)] then
|
||||
---@diagnostic disable-next-line: missing-fields LuaLS bug
|
||||
if scopes[key][M.range_id({iter_node:range()})] then
|
||||
return iter_node
|
||||
end
|
||||
iter_node = iter_node:parent()
|
||||
@@ -161,27 +269,36 @@ function M.containing_scope(node, bufnr, key)
|
||||
return nil
|
||||
end
|
||||
|
||||
local function _node_text(node, bufnr)
|
||||
local text = ts.get_node_text(node, bufnr)
|
||||
---@param info matchup.treesitter.MatchInfo
|
||||
---@return string
|
||||
local function text_until_newline(info)
|
||||
local text = info.text
|
||||
return text:match("([^\n]+).*")
|
||||
end
|
||||
|
||||
--- Fill in a match result based on a seed node
|
||||
function M.do_node_result(initial_node, bufnr, opts, side, key)
|
||||
---@param info matchup.treesitter.MatchInfo
|
||||
---@param bufnr integer
|
||||
---@param opts table<string, unknown>
|
||||
---@param side matchup.Side?
|
||||
---@param key string?
|
||||
function M.do_match_result(info, bufnr, opts, side, key)
|
||||
if not side or not key then
|
||||
return nil
|
||||
end
|
||||
|
||||
local scope = M.containing_scope(initial_node, bufnr, key)
|
||||
local scope = M.containing_scope(info, bufnr, key)
|
||||
if not scope then
|
||||
return nil
|
||||
end
|
||||
|
||||
local row, col, _ = initial_node:start()
|
||||
---@type integer, integer
|
||||
local row, col = unpack(info.range)
|
||||
|
||||
---@class matchup.Delim
|
||||
local result = {
|
||||
type = 'delim_py',
|
||||
match = _node_text(initial_node, bufnr),
|
||||
match = text_until_newline(info),
|
||||
side = side,
|
||||
lnum = row + 1,
|
||||
cnum = col + 1,
|
||||
@@ -191,9 +308,9 @@ function M.do_node_result(initial_node, bufnr, opts, side, key)
|
||||
_id = util.uuid4(),
|
||||
}
|
||||
|
||||
local info = {
|
||||
local cached_info = {
|
||||
bufnr = bufnr,
|
||||
initial_node = initial_node,
|
||||
info = info,
|
||||
row = row,
|
||||
col = col,
|
||||
key = key,
|
||||
@@ -201,11 +318,36 @@ function M.do_node_result(initial_node, bufnr, opts, side, key)
|
||||
search_range = {scope:range()},
|
||||
}
|
||||
|
||||
cache:set(result._id, info)
|
||||
cache:set(result._id, cached_info)
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
---@param info matchup.treesitter.MatchInfo
|
||||
---@param line integer
|
||||
---@param col integer
|
||||
---@return boolean
|
||||
local function is_in_range(info, line, col)
|
||||
---@type integer, integer, integer, integer
|
||||
local r_start_row, r_start_col, r_end_row, r_end_col = unpack(info.range)
|
||||
local p_start_row, p_start_col, p_end_row, p_end_col = line, col, line, col + 1
|
||||
|
||||
if p_start_row < r_start_row then
|
||||
return false
|
||||
elseif p_start_row == r_start_row and p_start_col < r_start_col then
|
||||
return false
|
||||
end
|
||||
|
||||
if p_end_row > r_end_row then
|
||||
return false
|
||||
elseif p_end_row == r_end_row and p_end_col > r_end_col then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
---@type table<matchup.Side, ('open'|'mid'|'close')[]>
|
||||
local side_table = {
|
||||
open = {'open'},
|
||||
mid = {'mid'},
|
||||
@@ -215,25 +357,32 @@ local side_table = {
|
||||
open_mid = {'mid', 'open'},
|
||||
}
|
||||
|
||||
---@alias matchup.Side 'open'|'mid'|'close'|'both'|'both_all'|'open_mid'
|
||||
---@alias matchup.Direction 'current'|'next'|'prev'
|
||||
---@alias matchup.Type 'delim_text'|'delim_all'|'all'
|
||||
|
||||
---@param bufnr integer
|
||||
---@param opts {direction: matchup.Direction, side: matchup.Side, type: matchup.Type}
|
||||
function M.get_delim(bufnr, opts)
|
||||
if opts.direction == 'current' then
|
||||
-- get current by query
|
||||
local active_nodes, symbols = unpack(M.get_active_nodes(bufnr))
|
||||
local active_matches, symbols = unpack(M.get_active_matches(bufnr))
|
||||
local cursor = api.nvim_win_get_cursor(0)
|
||||
|
||||
local smallest_len = 1e31
|
||||
---@type {info: matchup.treesitter.MatchInfo, side: matchup.Side, key: string}|nil
|
||||
local result_info = nil
|
||||
for _, side in ipairs(side_table[opts.side]) do
|
||||
if not(side == 'mid' and vim.g.matchup_delim_nomids > 0) then
|
||||
for _, node in ipairs(active_nodes[side]) do
|
||||
if utils2.is_in_node_range(node, cursor[1]-1, cursor[2]) then
|
||||
local len = ts_utils.node_length(node)
|
||||
for _, info in ipairs(active_matches[side] --[=[@as matchup.treesitter.MatchInfo[]]=]) do
|
||||
if is_in_range(info, cursor[1] - 1, cursor[2]) then
|
||||
local len = info.length
|
||||
if len < smallest_len then
|
||||
smallest_len = len
|
||||
result_info = {
|
||||
node = node,
|
||||
info = info,
|
||||
side = side,
|
||||
key = symbols[_node_id(node)]
|
||||
key = symbols[M.range_id(info.range)]
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -242,7 +391,7 @@ function M.get_delim(bufnr, opts)
|
||||
end
|
||||
|
||||
if result_info then
|
||||
return M.do_node_result(result_info.node, bufnr, opts,
|
||||
return M.do_match_result(result_info.info, bufnr, opts,
|
||||
result_info.side, result_info.key)
|
||||
end
|
||||
|
||||
@@ -253,16 +402,17 @@ function M.get_delim(bufnr, opts)
|
||||
-- look forwards or backwards for an active node
|
||||
local max_col = 1e5
|
||||
|
||||
local active_nodes, symbols = unpack(M.get_active_nodes(bufnr))
|
||||
local active_matches, symbols = unpack(M.get_active_matches(bufnr))
|
||||
|
||||
local cursor = api.nvim_win_get_cursor(0)
|
||||
local cur_pos = max_col * (cursor[1]-1) + cursor[2]
|
||||
local closest_node, closest_dist = nil, 1e31
|
||||
local closest_match, closest_dist = nil, 1e31
|
||||
local result_info = {}
|
||||
|
||||
for _, side in ipairs(side_table[opts.side]) do
|
||||
for _, node in ipairs(active_nodes[side]) do
|
||||
local row, col, _ = node:start()
|
||||
for _, info in ipairs(active_matches[side]--[=[@as matchup.treesitter.MatchInfo[]]=]) do
|
||||
---@type integer, integer
|
||||
local row, col = unpack(info.range)
|
||||
local pos = max_col * row + col
|
||||
|
||||
if opts.direction == 'next' and pos >= cur_pos
|
||||
@@ -271,61 +421,66 @@ function M.get_delim(bufnr, opts)
|
||||
local dist = math.abs(pos - cur_pos)
|
||||
if dist < closest_dist then
|
||||
closest_dist = dist
|
||||
closest_node = node
|
||||
result_info = { side=side, key=symbols[_node_id(node)] }
|
||||
closest_match = info
|
||||
result_info = { side=side, key=symbols[M.range_id(info.range)] }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if closest_node == nil then
|
||||
if closest_match == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
return M.do_node_result(closest_node, bufnr, opts,
|
||||
return M.do_match_result(closest_match, bufnr, opts,
|
||||
result_info.side, result_info.key)
|
||||
end
|
||||
|
||||
---@param delim matchup.Delim
|
||||
---@param down 1|0
|
||||
---@param bufnr integer
|
||||
---@return [string, integer, integer][]
|
||||
function M.get_matching(delim, down, bufnr)
|
||||
down = down > 0
|
||||
local is_down = down > 0
|
||||
|
||||
local info = cache:get(delim._id) or {}
|
||||
if info.bufnr ~= bufnr then
|
||||
local cached_info = cache:get(delim._id) or {}
|
||||
if cached_info.bufnr ~= bufnr then
|
||||
return {}
|
||||
end
|
||||
|
||||
local matches = {}
|
||||
local matches = {} ---@type [string, integer, integer][]
|
||||
|
||||
local sides
|
||||
local sides ---@type ('open'|'mid'|'close')[]
|
||||
if vim.g.matchup_delim_nomids > 0 then
|
||||
sides = down and {'close'} or {'open'}
|
||||
sides = is_down and {'close'} or {'open'}
|
||||
else
|
||||
sides = down and {'mid', 'close'} or {'mid', 'open'}
|
||||
sides = is_down and {'mid', 'close'} or {'mid', 'open'}
|
||||
end
|
||||
|
||||
local active_nodes, symbols = unpack(M.get_active_nodes(bufnr))
|
||||
local active_matches, symbols = unpack(M.get_active_matches(bufnr))
|
||||
|
||||
local got_close = false
|
||||
|
||||
local stop_time = _time() + vim.fn['matchup#perf#timeout']()
|
||||
local stop_time = _time() + vim.fn['matchup#perf#timeout']() ---@type number
|
||||
|
||||
for _, side in ipairs(sides) do
|
||||
for _, node in ipairs(active_nodes[side]) do
|
||||
local row, col, _ = node:start()
|
||||
for _, info in ipairs(active_matches[side]--[=[@as matchup.treesitter.MatchInfo[]]=]) do
|
||||
---@type integer, integer
|
||||
local row, col = unpack(info.range)
|
||||
|
||||
if _time() > stop_time then
|
||||
return {}
|
||||
end
|
||||
|
||||
if info.initial_node ~= node and symbols[_node_id(node)] == info.key
|
||||
and (down and (row > info.row or row == info.row and col > info.col)
|
||||
or not down and (row < info.row or row == info.row and col < info.col))
|
||||
and (row >= info.search_range[1]
|
||||
and row <= info.search_range[3]) then
|
||||
if cached_info.info ~= info and symbols[M.range_id(info.range)] == cached_info.key
|
||||
and (is_down and (row > cached_info.row or row == cached_info.row and col > cached_info.col)
|
||||
or not is_down and (row < cached_info.row or row == cached_info.row and col < cached_info.col))
|
||||
and (row >= cached_info.search_range[1]
|
||||
and row <= cached_info.search_range[3]) then
|
||||
|
||||
local target_scope = M.containing_scope(node, bufnr, info.key)
|
||||
if info.scope == target_scope then
|
||||
local text = _node_text(node, bufnr) or ''
|
||||
local target_scope = M.containing_scope(info, bufnr, cached_info.key)
|
||||
if cached_info.scope == target_scope then
|
||||
local text = text_until_newline(info) or ''
|
||||
table.insert(matches, {text, row + 1, col + 1})
|
||||
|
||||
if side == 'close' then
|
||||
@@ -342,45 +497,12 @@ function M.get_matching(delim, down, bufnr)
|
||||
end)
|
||||
|
||||
-- no stop marker is found, use enclosing scope
|
||||
if down and not got_close then
|
||||
local row, col, _ = info.scope:end_()
|
||||
if is_down and not got_close then
|
||||
local row, col, _ = cached_info.scope:end_()
|
||||
table.insert(matches, {'', row + 1, col + 1})
|
||||
end
|
||||
|
||||
return matches
|
||||
end
|
||||
|
||||
local function opt_tbl_for_lang(opt, lang)
|
||||
local is_table = type(opt) == "table"
|
||||
if opt and (not is_table or vim.tbl_contains(opt, lang)) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function M.get_option(bufnr, opt_name)
|
||||
local config = configs.get_module('matchup') or {}
|
||||
local lang = parsers.get_buf_lang(bufnr)
|
||||
if (opt_name == 'include_match_words'
|
||||
or opt_name == 'additional_vim_regex_highlighting'
|
||||
or opt_name == 'disable_virtual_text'
|
||||
or opt_name == 'enable_quotes') then
|
||||
return opt_tbl_for_lang(config[opt_name], lang)
|
||||
end
|
||||
error('invalid option ' .. opt_name)
|
||||
end
|
||||
|
||||
function M.attach(bufnr, lang)
|
||||
if M.get_option(bufnr, 'additional_vim_regex_highlighting')
|
||||
and api.nvim_buf_get_option(bufnr, 'syntax') == '' then
|
||||
api.nvim_buf_set_option(bufnr, 'syntax', 'ON')
|
||||
end
|
||||
|
||||
api.nvim_call_function('matchup#ts_engine#attach', {bufnr, lang})
|
||||
end
|
||||
|
||||
function M.detach(bufnr)
|
||||
api.nvim_call_function('matchup#ts_engine#detach', {bufnr})
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -1,60 +1,37 @@
|
||||
if not pcall(require, 'nvim-treesitter') then
|
||||
return {
|
||||
is_active = function() return false end,
|
||||
synID = function(lnum, col, transparent)
|
||||
return vim.fn.synID(lnum, col, transparent)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
local api = vim.api
|
||||
local vts = vim.treesitter
|
||||
local hl_info = require'treesitter-matchup.third-party.hl-info'
|
||||
local queries = require'treesitter-matchup.third-party.query'
|
||||
local ts_utils = require'nvim-treesitter.ts_utils'
|
||||
local parsers = require'nvim-treesitter.parsers'
|
||||
local internal = require'treesitter-matchup.internal'
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param bufnr integer?
|
||||
---@return boolean
|
||||
function M.is_active(bufnr)
|
||||
bufnr = bufnr or api.nvim_get_current_buf()
|
||||
return (hl_info.active()
|
||||
and api.nvim_buf_get_option(bufnr, 'syntax') == '')
|
||||
and vim.bo[bufnr].syntax == '')
|
||||
end
|
||||
|
||||
--- Get all nodes that are marked as skip
|
||||
---@param bufnr integer
|
||||
function M.get_skips(bufnr)
|
||||
local matches = queries.get_matches(bufnr, 'matchup')
|
||||
local matches = internal.get_matches(bufnr)
|
||||
|
||||
local skips = {}
|
||||
local skips = {} ---@type table<string, 1>
|
||||
|
||||
for _, match in ipairs(matches) do
|
||||
if match.skip then
|
||||
skips[match.skip.node:id()] = 1
|
||||
skips[internal.range_id(match.skip.info.range)] = 1
|
||||
end
|
||||
end
|
||||
|
||||
return skips
|
||||
end
|
||||
|
||||
local function get_node_at_pos(cursor)
|
||||
local cursor_range = { cursor[1] - 1, cursor[2] }
|
||||
|
||||
local buf = vim.api.nvim_win_get_buf(0)
|
||||
local root_lang_tree = parsers.get_parser(buf)
|
||||
if not root_lang_tree then
|
||||
return
|
||||
end
|
||||
local root = ts_utils.get_root_for_position(
|
||||
cursor_range[1], cursor_range[2], root_lang_tree)
|
||||
|
||||
if not root then
|
||||
return
|
||||
end
|
||||
|
||||
return root:named_descendant_for_range(
|
||||
cursor_range[1], cursor_range[2], cursor_range[1], cursor_range[2])
|
||||
end
|
||||
|
||||
---@param lnum integer
|
||||
---@param col integer
|
||||
---@return boolean
|
||||
function M.lang_skip(lnum, col)
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local skips = M.get_skips(bufnr)
|
||||
@@ -63,17 +40,21 @@ function M.lang_skip(lnum, col)
|
||||
return false
|
||||
end
|
||||
|
||||
local node = get_node_at_pos({lnum, col - 1})
|
||||
local node = vts.get_node({pos = {lnum - 1, col - 1}})
|
||||
if not node then
|
||||
return false
|
||||
end
|
||||
if skips[node:id()] then
|
||||
---@diagnostic disable-next-line: missing-fields LuaLS bug
|
||||
if skips[internal.range_id({node:range()})] then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
---@param lnum integer
|
||||
---@param col integer
|
||||
---@param transparent 1|0
|
||||
function M.synID(lnum, col, transparent)
|
||||
if not M.is_active() then
|
||||
return vim.fn.synID(lnum, col, transparent)
|
||||
|
||||
394
lua/treesitter-matchup/third-party/query.lua
vendored
394
lua/treesitter-matchup/third-party/query.lua
vendored
@@ -1,394 +0,0 @@
|
||||
-- From https://github.com/nvim-treesitter/nvim-treesitter
|
||||
-- Copyright 2021
|
||||
-- licensed under the Apache License 2.0
|
||||
-- See nvim-treesitter.LICENSE-APACHE-2.0
|
||||
|
||||
local api = vim.api
|
||||
local ts = require 'treesitter-matchup.compat'
|
||||
local tsrange = require "nvim-treesitter.tsrange"
|
||||
local utils = require "nvim-treesitter.utils"
|
||||
local parsers = require "nvim-treesitter.parsers"
|
||||
local caching = require "nvim-treesitter.caching"
|
||||
|
||||
local M = {}
|
||||
|
||||
local EMPTY_ITER = function() end
|
||||
|
||||
do
|
||||
local query_cache = caching.create_buffer_cache()
|
||||
|
||||
local function update_cached_matches(bufnr, changed_tick, query_group)
|
||||
query_cache.set(query_group, bufnr, {
|
||||
tick = changed_tick,
|
||||
cache = M.collect_group_results(bufnr, query_group) or {},
|
||||
})
|
||||
end
|
||||
|
||||
function M.get_matches(bufnr, query_group)
|
||||
bufnr = bufnr or api.nvim_get_current_buf()
|
||||
local cached_local = query_cache.get(query_group, bufnr)
|
||||
if not cached_local or api.nvim_buf_get_changedtick(bufnr) > cached_local.tick then
|
||||
update_cached_matches(bufnr, api.nvim_buf_get_changedtick(bufnr), query_group)
|
||||
end
|
||||
|
||||
return query_cache.get(query_group, bufnr).cache
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local mt = {}
|
||||
mt.__index = function(tbl, key)
|
||||
if rawget(tbl, key) == nil then
|
||||
rawset(tbl, key, {})
|
||||
end
|
||||
return rawget(tbl, key)
|
||||
end
|
||||
|
||||
-- cache will auto set the table for each lang if it is nil
|
||||
local cache = setmetatable({}, mt)
|
||||
|
||||
--- Same as `vim.treesitter.query` except will return cached values
|
||||
---@param lang string
|
||||
---@param query_name string
|
||||
function M.get_query(lang, query_name)
|
||||
if cache[lang][query_name] == nil then
|
||||
cache[lang][query_name] = ts.get_query(lang, query_name)
|
||||
end
|
||||
|
||||
return cache[lang][query_name]
|
||||
end
|
||||
|
||||
--- Invalidates the query file cache.
|
||||
--- If lang and query_name is both present, will reload for only the lang and query_name.
|
||||
--- If only lang is present, will reload all query_names for that lang
|
||||
--- If none are present, will reload everything
|
||||
---@param lang string
|
||||
---@param query_name string
|
||||
function M.invalidate_query_cache(lang, query_name)
|
||||
if lang and query_name then
|
||||
cache[lang][query_name] = nil
|
||||
elseif lang and not query_name then
|
||||
for query_name0, _ in pairs(cache[lang]) do
|
||||
M.invalidate_query_cache(lang, query_name0)
|
||||
end
|
||||
elseif not lang and not query_name then
|
||||
for lang0, _ in pairs(cache) do
|
||||
for query_name0, _ in pairs(cache[lang0]) do
|
||||
M.invalidate_query_cache(lang0, query_name0)
|
||||
end
|
||||
end
|
||||
else
|
||||
error "Cannot have query_name by itself!"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- This function is meant for an autocommand and not to be used. Only use if file is a query file.
|
||||
---@param fname string
|
||||
function M.invalidate_query_file(fname)
|
||||
local fnamemodify = vim.fn.fnamemodify
|
||||
M.invalidate_query_cache(fnamemodify(fname, ":p:h:t"), fnamemodify(fname, ":t:r"))
|
||||
end
|
||||
|
||||
---@class QueryInfo
|
||||
---@field root LanguageTree
|
||||
---@field source integer
|
||||
---@field start integer
|
||||
---@field stop integer
|
||||
|
||||
---@param bufnr integer
|
||||
---@param query_name string
|
||||
---@param root LanguageTree
|
||||
---@param root_lang string|nil
|
||||
---@return Query|nil, QueryInfo|nil
|
||||
local function prepare_query(bufnr, query_name, root, root_lang)
|
||||
local buf_lang = parsers.get_buf_lang(bufnr)
|
||||
|
||||
if not buf_lang then
|
||||
return
|
||||
end
|
||||
|
||||
local parser = parsers.get_parser(bufnr, buf_lang)
|
||||
if not parser then
|
||||
return
|
||||
end
|
||||
|
||||
if not root then
|
||||
local first_tree = parser:trees()[1]
|
||||
|
||||
if first_tree then
|
||||
root = first_tree:root()
|
||||
end
|
||||
end
|
||||
|
||||
if not root then
|
||||
return
|
||||
end
|
||||
|
||||
local range = { root:range() }
|
||||
|
||||
if not root_lang then
|
||||
local lang_tree = parser:language_for_range(range)
|
||||
|
||||
if lang_tree then
|
||||
root_lang = lang_tree:lang()
|
||||
end
|
||||
end
|
||||
|
||||
if not root_lang then
|
||||
return
|
||||
end
|
||||
|
||||
local query = M.get_query(root_lang, query_name)
|
||||
if not query then
|
||||
return
|
||||
end
|
||||
|
||||
return query,
|
||||
{
|
||||
root = root,
|
||||
source = bufnr,
|
||||
start = range[1],
|
||||
-- The end row is exclusive so we need to add 1 to it.
|
||||
stop = range[3] + 1,
|
||||
}
|
||||
end
|
||||
|
||||
local function get_byte_offset(buf, row, col)
|
||||
local lines = api.nvim_buf_get_lines(buf, row, row + 1, false)
|
||||
if #lines < 1 then
|
||||
return
|
||||
end
|
||||
return api.nvim_buf_get_offset(buf, row) + vim.fn.byteidx(lines[1], col)
|
||||
end
|
||||
|
||||
local function TSRange_from_table(buf, range)
|
||||
return setmetatable(
|
||||
{
|
||||
start_pos = {range[1], range[2], get_byte_offset(buf, range[1], range[2])},
|
||||
end_pos = {range[3], range[4], get_byte_offset(buf, range[3], range[4])},
|
||||
buf = buf,
|
||||
[1] = range[1],
|
||||
[2] = range[2],
|
||||
[3] = range[3],
|
||||
[4] = range[4],
|
||||
},
|
||||
tsrange.TSRange)
|
||||
end
|
||||
|
||||
---@param query Query
|
||||
---@param bufnr integer
|
||||
---@param start_row integer
|
||||
---@param end_row integer
|
||||
function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row)
|
||||
-- A function that splits a string on '.'
|
||||
local function split(string)
|
||||
local t = {}
|
||||
for str in string.gmatch(string, "([^.]+)") do
|
||||
table.insert(t, str)
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
-- Given a path (i.e. a List(String)) this functions inserts value at path
|
||||
local function insert_to_path(object, path, value)
|
||||
local curr_obj = object
|
||||
|
||||
for index = 1, (#path - 1) do
|
||||
if curr_obj[path[index]] == nil then
|
||||
curr_obj[path[index]] = {}
|
||||
end
|
||||
|
||||
curr_obj = curr_obj[path[index]]
|
||||
end
|
||||
|
||||
curr_obj[path[#path]] = value
|
||||
end
|
||||
|
||||
local matches = query:iter_matches(qnode, bufnr, start_row, end_row, { all = false })
|
||||
|
||||
local function iterator()
|
||||
local pattern, match, metadata = matches()
|
||||
if pattern ~= nil then
|
||||
local prepared_match = {}
|
||||
|
||||
-- Extract capture names from each match
|
||||
for id, node in pairs(match) do
|
||||
local name = query.captures[id] -- name of the capture in the query
|
||||
if name ~= nil then
|
||||
local path = split(name .. ".node")
|
||||
insert_to_path(prepared_match, path, node)
|
||||
local metadata_path = split(name .. ".metadata")
|
||||
insert_to_path(prepared_match, metadata_path, metadata[id])
|
||||
end
|
||||
end
|
||||
|
||||
-- Add some predicates for testing
|
||||
local preds = query.info.patterns[pattern]
|
||||
if preds then
|
||||
for _, pred in pairs(preds) do
|
||||
-- functions
|
||||
if pred[1] == "set!" and type(pred[2]) == "string" then
|
||||
insert_to_path(prepared_match, split(pred[2]), pred[3])
|
||||
end
|
||||
if pred[1] == "make-range!" and #pred == 4 then
|
||||
assert(type(pred[2]) == "string")
|
||||
local path = pred[2]
|
||||
insert_to_path(
|
||||
prepared_match,
|
||||
split(path .. ".node"),
|
||||
tsrange.TSRange.from_nodes(bufnr, match[pred[3]], match[pred[4]])
|
||||
)
|
||||
end
|
||||
if pred[1] == "offset!" then
|
||||
local path = type(pred[2]) == "string" and pred[2] or query.captures[pred[2]]
|
||||
|
||||
local offset_node = match[pred[2]]
|
||||
local range = {offset_node:range()}
|
||||
local start_row_offset = pred[3] or 0
|
||||
local start_col_offset = pred[4] or 0
|
||||
local end_row_offset = pred[5] or 0
|
||||
local end_col_offset = pred[6] or 0
|
||||
|
||||
range[1] = range[1] + start_row_offset
|
||||
range[2] = range[2] + start_col_offset
|
||||
range[3] = range[3] + end_row_offset
|
||||
range[4] = range[4] + end_col_offset
|
||||
|
||||
insert_to_path(prepared_match, split(path..'.node'),
|
||||
TSRange_from_table(bufnr, range))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return prepared_match
|
||||
end
|
||||
end
|
||||
return iterator
|
||||
end
|
||||
|
||||
--- Return all nodes corresponding to a specific capture path (like @definition.var, @reference.type)
|
||||
---Works like M.get_references or M.get_scopes except you can choose the capture
|
||||
---Can also be a nested capture like @definition.function to get all nodes defining a function.
|
||||
---
|
||||
---@param bufnr integer the buffer
|
||||
---@param captures string|string[]
|
||||
---@param query_group string the name of query group (highlights or injections for example)
|
||||
---@param root LanguageTree|nil node from where to start the search
|
||||
---@param lang string|nil the language from where to get the captures.
|
||||
--- Root nodes can have several languages.
|
||||
---@return table|nil
|
||||
function M.get_capture_matches(bufnr, captures, query_group, root, lang)
|
||||
if type(captures) == "string" then
|
||||
captures = { captures }
|
||||
end
|
||||
local strip_captures = {}
|
||||
for i, capture in ipairs(captures) do
|
||||
if capture:sub(1, 1) ~= "@" then
|
||||
error 'Captures must start with "@"'
|
||||
return
|
||||
end
|
||||
-- Remove leading "@".
|
||||
strip_captures[i] = capture:sub(2)
|
||||
end
|
||||
|
||||
local matches = {}
|
||||
for match in M.iter_group_results(bufnr, query_group, root, lang) do
|
||||
for _, capture in ipairs(strip_captures) do
|
||||
local insert = utils.get_at_path(match, capture)
|
||||
if insert then
|
||||
table.insert(matches, insert)
|
||||
end
|
||||
end
|
||||
end
|
||||
return matches
|
||||
end
|
||||
|
||||
function M.iter_captures(bufnr, query_name, root, lang)
|
||||
local query, params = prepare_query(bufnr, query_name, root, lang)
|
||||
if not query then
|
||||
return EMPTY_ITER
|
||||
end
|
||||
assert(params)
|
||||
|
||||
local iter = query:iter_captures(params.root, params.source, params.start, params.stop)
|
||||
|
||||
local function wrapped_iter()
|
||||
local id, node, metadata = iter()
|
||||
if not id then
|
||||
return
|
||||
end
|
||||
|
||||
local name = query.captures[id]
|
||||
if string.sub(name, 1, 1) == "_" then
|
||||
return wrapped_iter()
|
||||
end
|
||||
|
||||
return name, node, metadata
|
||||
end
|
||||
|
||||
return wrapped_iter
|
||||
end
|
||||
|
||||
---Iterates matches from a query file.
|
||||
---@param bufnr integer the buffer
|
||||
---@param query_group string the query file to use
|
||||
---@param root LanguageTree the root node
|
||||
---@param root_lang string|nil the root node lang, if known
|
||||
function M.iter_group_results(bufnr, query_group, root, root_lang)
|
||||
local query, params = prepare_query(bufnr, query_group, root, root_lang)
|
||||
if not query then
|
||||
return EMPTY_ITER
|
||||
end
|
||||
assert(params)
|
||||
|
||||
return M.iter_prepared_matches(query, params.root, params.source, params.start, params.stop)
|
||||
end
|
||||
|
||||
function M.collect_group_results(bufnr, query_group, root, lang)
|
||||
local matches = {}
|
||||
|
||||
for prepared_match in M.iter_group_results(bufnr, query_group, root, lang) do
|
||||
table.insert(matches, prepared_match)
|
||||
end
|
||||
|
||||
return matches
|
||||
end
|
||||
|
||||
---@alias CaptureResFn function(string, LanguageTree, LanguageTree): string, string
|
||||
|
||||
--- Same as get_capture_matches except this will recursively get matches for every language in the tree.
|
||||
---@param bufnr integer The bufnr
|
||||
---@param capture_or_fn string|CaptureResFn The capture to get. If a function is provided then that
|
||||
--- function will be used to resolve both the capture and query argument.
|
||||
--- The function can return `nil` to ignore that tree.
|
||||
---@param query_type string The query to get the capture from. This is ignore if a function is provided
|
||||
--- for the captuer argument.
|
||||
function M.get_capture_matches_recursively(bufnr, capture_or_fn, query_type)
|
||||
---@type CaptureResFn
|
||||
local type_fn
|
||||
if type(capture_or_fn) == "function" then
|
||||
type_fn = capture_or_fn
|
||||
else
|
||||
type_fn = function(_, _, _)
|
||||
return capture_or_fn, query_type
|
||||
end
|
||||
end
|
||||
local parser = parsers.get_parser(bufnr)
|
||||
local matches = {}
|
||||
|
||||
if parser then
|
||||
parser:for_each_tree(function(tree, lang_tree)
|
||||
local lang = lang_tree:lang()
|
||||
local capture, type_ = type_fn(lang, tree, lang_tree)
|
||||
|
||||
if capture then
|
||||
vim.list_extend(matches, M.get_capture_matches(bufnr, capture, type_, tree:root(), lang))
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return matches
|
||||
end
|
||||
|
||||
return M
|
||||
28
lua/treesitter-matchup/third-party/ts-utils.lua
vendored
Normal file
28
lua/treesitter-matchup/third-party/ts-utils.lua
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
-- From https://github.com/nvim-treesitter/nvim-treesitter
|
||||
-- Copyright 2021
|
||||
-- licensed under the Apache License 2.0
|
||||
-- See nvim-treesitter.LICENSE-APACHE-2.0
|
||||
|
||||
local M = {}
|
||||
|
||||
---Memoize a function using hash_fn to hash the arguments.
|
||||
---@generic F: function
|
||||
---@param fn F
|
||||
---@param hash_fn fun(...): any
|
||||
---@return F
|
||||
function M.memoize(fn, hash_fn)
|
||||
local cache = setmetatable({}, { __mode = 'kv' }) ---@type table<any,any>
|
||||
|
||||
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
|
||||
|
||||
return M
|
||||
@@ -5,6 +5,7 @@ COVER = covimerage -q run --append --no-report \
|
||||
--source $(CURDIR)/../../plugin
|
||||
MYVIM ?= nvim --headless
|
||||
MAKEFLAGS += --no-print-directory
|
||||
VENV = . env/bin/activate;
|
||||
|
||||
TESTS := $(wildcard test-*)
|
||||
|
||||
@@ -19,27 +20,24 @@ sysinfo:
|
||||
@echo "**** SYSTEM INFORMATION ****"
|
||||
|
||||
$(TESTS): env
|
||||
@. env/bin/activate
|
||||
mkdir -p cov.tmp
|
||||
MYVIM="$(COVER) $(MYVIM)" $(MAKE) -C $@
|
||||
$(VENV) mkdir -p cov.tmp
|
||||
$(VENV) MYVIM="$(COVER) $(MYVIM)" $(MAKE) -C $@
|
||||
|
||||
coverage: coverage.xml
|
||||
|
||||
cov.tmp/coverage_covimerage: $(wildcard cov.tmp/_*)
|
||||
coverage combine $^
|
||||
$(VENV) coverage combine $^
|
||||
|
||||
coverage.xml: env cov.tmp/coverage_covimerage
|
||||
. env/bin/activate
|
||||
coverage report -m
|
||||
coverage html
|
||||
coverage xml
|
||||
$(VENV) coverage report -m
|
||||
$(VENV) coverage html
|
||||
$(VENV) coverage xml
|
||||
|
||||
env: env/pyvenv.cfg
|
||||
|
||||
env/pyvenv.cfg:
|
||||
python3 -m venv env
|
||||
. env/bin/activate
|
||||
pip install -r requirements.txt
|
||||
$(VENV) pip install -r requirements.txt
|
||||
|
||||
ifndef MAKECMDGOALS
|
||||
test: sysinfo
|
||||
|
||||
@@ -3,23 +3,6 @@ set packpath-=~/.config/nvim packpath-=~/.config/nvim/after
|
||||
let &rtp = '../../..,' . &rtp
|
||||
let &rtp = &rtp . ',../../../after'
|
||||
|
||||
if $TESTS_ENABLE_TREESITTER
|
||||
let s:path = simplify(expand('<sfile>:h').'/../../..')
|
||||
let &rtp = s:path.'/test/vader/plugged/nvim-treesitter,' . &rtp
|
||||
let &rtp .= ','.s:path.'/test/vader/plugged/nvim-treesitter/after'
|
||||
|
||||
runtime! plugin/nvim-treesitter.vim
|
||||
runtime! plugin/nvim-treesitter.lua
|
||||
|
||||
lua <<EOF
|
||||
require'nvim-treesitter.configs'.setup {
|
||||
matchup = {
|
||||
enable = true
|
||||
}
|
||||
}
|
||||
EOF
|
||||
endif
|
||||
|
||||
filetype plugin indent on
|
||||
syntax enable
|
||||
|
||||
|
||||
@@ -5,33 +5,16 @@ if !$TESTS_ENABLE_TREESITTER && $MODE > 0
|
||||
call matchup#test#finished()
|
||||
endif
|
||||
|
||||
let s:expect_ts_engine = +$TESTS_ENABLE_TREESITTER
|
||||
let g:matchup_treesitter_enabled = v:false
|
||||
let s:expect_ts_engine = $MODE == 0 ? 0 : +$TESTS_ENABLE_TREESITTER
|
||||
|
||||
if $MODE == 1
|
||||
lua <<EOF
|
||||
require'nvim-treesitter.configs'.setup {
|
||||
highlight = { enable = true },
|
||||
matchup = { enable = true }
|
||||
}
|
||||
EOF
|
||||
let g:matchup_treesitter_enabled = v:true
|
||||
autocmd FileType *.rb lua vim.treesitter.start()
|
||||
elseif $MODE == 2
|
||||
lua <<EOF
|
||||
require'nvim-treesitter.configs'.setup {
|
||||
highlight = { enable = true },
|
||||
matchup = {
|
||||
enable = true,
|
||||
additional_vim_regex_highlighting = true
|
||||
}
|
||||
}
|
||||
EOF
|
||||
let g:matchup_treesitter_enabled = v:true
|
||||
elseif $MODE == 3
|
||||
lua <<EOF
|
||||
require'nvim-treesitter.configs'.setup {
|
||||
highlight = { enable = true },
|
||||
matchup = { enable = false }
|
||||
}
|
||||
EOF
|
||||
|
||||
let g:matchup_treesitter_enabled = v:false
|
||||
let s:expect_ts_engine = 0
|
||||
endif
|
||||
|
||||
|
||||
@@ -12,22 +12,6 @@ let &rtp = s:path.'/test/rtp,' . &rtp
|
||||
" load other plugins, if necessary
|
||||
" let &rtp = '~/path/to/other/plugin,' . &rtp
|
||||
|
||||
if $TESTS_ENABLE_TREESITTER
|
||||
let &rtp = s:path.'/test/vader/plugged/nvim-treesitter,' . &rtp
|
||||
let &rtp .= ','.s:path.'/test/vader/plugged/nvim-treesitter/after'
|
||||
|
||||
runtime! plugin/nvim-treesitter.vim
|
||||
runtime! plugin/nvim-treesitter.lua
|
||||
|
||||
lua <<EOF
|
||||
require'nvim-treesitter.configs'.setup {
|
||||
matchup = {
|
||||
enable = true
|
||||
}
|
||||
}
|
||||
EOF
|
||||
endif
|
||||
|
||||
if empty(globpath(&rtp, 'plugin/vader.vim'))
|
||||
echoerr 'vader not found'
|
||||
exit!
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
Execute (Helper):
|
||||
function! TSActive()
|
||||
return exists(':TSInstall')
|
||||
endfunction
|
||||
|
||||
if TSActive()
|
||||
Log 'nvim-treesitter active'
|
||||
else
|
||||
Log 'nvim-treesitter not active'
|
||||
endif
|
||||
|
||||
Given python (A python script):
|
||||
def F(x, y):
|
||||
if x == 1:
|
||||
@@ -35,22 +24,22 @@ Before (Cursor):
|
||||
Do (Move %):
|
||||
%
|
||||
Then (Verify line):
|
||||
AssertEqual (TSActive() ? 4 : 2), line('.')
|
||||
AssertEqual (len(b:matchup_active_engines.delim_all) == 2 ? 4 : 2), line('.')
|
||||
|
||||
Do (Move % twice):
|
||||
%%
|
||||
Then (Verify line):
|
||||
AssertEqual (TSActive() ? 11 : 2), line('.')
|
||||
AssertEqual (len(b:matchup_active_engines.delim_all) == 2 ? 11 : 2), line('.')
|
||||
|
||||
Do (Move % 3 times):
|
||||
%%%
|
||||
Then (Verify line):
|
||||
AssertEqual (TSActive() ? 2 : 2), line('.')
|
||||
AssertEqual (len(b:matchup_active_engines.delim_all) == 2 ? 2 : 2), line('.')
|
||||
|
||||
Do (Move % 4 times):
|
||||
%%%%
|
||||
Then (Verify line):
|
||||
AssertEqual (TSActive() ? 4 : 2), line('.')
|
||||
AssertEqual (len(b:matchup_active_engines.delim_all) == 2 ? 4 : 2), line('.')
|
||||
|
||||
# ----- inner if/elif/else -----
|
||||
|
||||
@@ -60,19 +49,19 @@ Before (Cursor):
|
||||
Do (Inner: Move %):
|
||||
%
|
||||
Then (Verify line):
|
||||
AssertEqual (TSActive() ? 7 : 5), line('.')
|
||||
AssertEqual (len(b:matchup_active_engines.delim_all) == 2 ? 7 : 5), line('.')
|
||||
|
||||
Do (Inner: % 2 times):
|
||||
%%
|
||||
Then (Verify line):
|
||||
AssertEqual (TSActive() ? 9 : 5), line('.')
|
||||
AssertEqual (len(b:matchup_active_engines.delim_all) == 2 ? 9 : 5), line('.')
|
||||
|
||||
Do (Inner: % 3 times):
|
||||
%%%
|
||||
Then (Verify line):
|
||||
AssertEqual (TSActive() ? 5 : 5), line('.')
|
||||
AssertEqual (len(b:matchup_active_engines.delim_all) == 2 ? 5 : 5), line('.')
|
||||
|
||||
Do (Inner: % 4 times):
|
||||
%%%%
|
||||
Then (Verify line):
|
||||
AssertEqual (TSActive() ? 7 : 5), line('.')
|
||||
AssertEqual (len(b:matchup_active_engines.delim_all) == 2 ? 7 : 5), line('.')
|
||||
|
||||
61
vim.Dockerfile
Normal file
61
vim.Dockerfile
Normal file
@@ -0,0 +1,61 @@
|
||||
FROM debian:latest AS neovim-image
|
||||
ARG NVIM_VERSION=stable
|
||||
ARG NVIM_ARCH=-linux-x86_64
|
||||
ADD --chmod=755 https://github.com/neovim/neovim/releases/download/${NVIM_VERSION}/nvim${NVIM_ARCH}.appimage /nvim-linux-x86_64.appimage
|
||||
RUN /nvim-linux-x86_64.appimage --appimage-extract
|
||||
|
||||
FROM debian:latest AS vim-image
|
||||
ARG VIM_VERSION=v9.1.1287
|
||||
ADD --chmod=755 https://github.com/vim/vim-appimage/releases/download/${VIM_VERSION}/Vim-${VIM_VERSION}.glibc2.29-x86_64.AppImage /vim-linux-x86_64.appimage
|
||||
RUN /vim-linux-x86_64.appimage --appimage-extract
|
||||
|
||||
FROM rust:latest AS tree-sitter
|
||||
WORKDIR /work
|
||||
RUN cargo install tree-sitter-cli --root /
|
||||
ADD https://github.com/tree-sitter/tree-sitter-ruby.git /work/tree-sitter-ruby
|
||||
RUN cd tree-sitter-ruby \
|
||||
&& tree-sitter build -o /work/ruby.so
|
||||
ADD https://github.com/tree-sitter/tree-sitter-python.git /work/tree-sitter-python
|
||||
RUN cd tree-sitter-python \
|
||||
&& tree-sitter build -o /work/python.so
|
||||
|
||||
FROM python:latest AS base
|
||||
RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
|
||||
--mount=target=/var/cache/apt,type=cache,sharing=locked \
|
||||
apt-get update -qq && \
|
||||
apt-get install --no-install-recommends -y \
|
||||
git \
|
||||
ca-certificates \
|
||||
make
|
||||
|
||||
FROM base AS test-prep
|
||||
WORKDIR /work
|
||||
COPY test/new/requirements.txt test/new/requirements.txt
|
||||
COPY test/new/Makefile test/new/Makefile
|
||||
RUN cd test/new && make env
|
||||
RUN mkdir -p test/vader/vader.vim && git clone --depth=1 https://github.com/junegunn/vader.vim.git test/vader/vader.vim
|
||||
|
||||
FROM python:latest AS nvim
|
||||
|
||||
WORKDIR /work
|
||||
ENV HOME=/work
|
||||
ENV GIT_PAGER=cat
|
||||
ENV TESTS_ENABLE_TREESITTER=1
|
||||
|
||||
# nvim
|
||||
COPY --from=neovim-image /squashfs-root /nvim-root
|
||||
RUN ln -s /nvim-root/AppRun /bin/nvim
|
||||
|
||||
# vim
|
||||
COPY --from=vim-image /squashfs-root /vim-root
|
||||
RUN ln -s /vim-root/AppRun /bin/vim
|
||||
|
||||
COPY . .
|
||||
COPY --from=test-prep /work/test test
|
||||
|
||||
# Treesitter
|
||||
RUN mkdir -p /work/.local/share/nvim/site/parser/
|
||||
COPY --from=tree-sitter /work/ruby.so /work/.local/share/nvim/site/parser/ruby.so
|
||||
COPY --from=tree-sitter /work/python.so /work/.local/share/nvim/site/parser/python.so
|
||||
|
||||
ENTRYPOINT ["bash"]
|
||||
Reference in New Issue
Block a user