retrovim 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.conda/retrovim.yaml +259 -0
- package/.conda/terax.icns +0 -0
- package/.conda/terax.ico +0 -0
- package/.conda/terax.png +0 -0
- package/.github/workflows/release.yml +95 -0
- package/.gitmodules +3 -0
- package/.npm/kanata_touchcursor.js +28 -0
- package/.npm/nvim.js +26 -0
- package/.npm/yazi.js +26 -0
- package/.npm/zsh.js +17 -0
- package/.pip/kanata_touchcursor/__init__.py +28 -0
- package/.pip/nvim/__init__.py +31 -0
- package/.pip/yazi/__init__.py +31 -0
- package/.pip/zsh/__init__.py +22 -0
- package/CHANGELOG.md +26 -0
- package/LICENSE +674 -0
- package/README.md +336 -0
- package/kanata/touchcursor.kbd +164 -0
- package/nvim/init.lua +813 -0
- package/nvim/plugins/mini.nvim/.github/DISCUSSION_TEMPLATE/q-a.yml +72 -0
- package/nvim/plugins/mini.nvim/.github/ISSUE_TEMPLATE/bug-report.yml +136 -0
- package/nvim/plugins/mini.nvim/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/nvim/plugins/mini.nvim/.github/ISSUE_TEMPLATE/feature-request.yml +75 -0
- package/nvim/plugins/mini.nvim/.github/PULL_REQUEST_TEMPLATE.md +2 -0
- package/nvim/plugins/mini.nvim/.github/workflows/quality-control.yml +150 -0
- package/nvim/plugins/mini.nvim/.pre-commit-config.yaml +20 -0
- package/nvim/plugins/mini.nvim/.stylua.toml +7 -0
- package/nvim/plugins/mini.nvim/.styluaignore +1 -0
- package/nvim/plugins/mini.nvim/CHANGELOG.md +1894 -0
- package/nvim/plugins/mini.nvim/CODE_OF_CONDUCT.md +132 -0
- package/nvim/plugins/mini.nvim/CONTRIBUTING.md +331 -0
- package/nvim/plugins/mini.nvim/LICENSE +21 -0
- package/nvim/plugins/mini.nvim/MAINTAINING.md +330 -0
- package/nvim/plugins/mini.nvim/Makefile +51 -0
- package/nvim/plugins/mini.nvim/README.md +261 -0
- package/nvim/plugins/mini.nvim/TESTING.md +1011 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/README.md +35 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/benchmark.sh +56 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_dashboard-alpha.lua +21 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_dashboard-original.lua +17 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_dashboard-starter.lua +18 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_empty.lua +4 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_starter-default.lua +7 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_startify-alpha.lua +10 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_startify-original.lua +7 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_startify-starter.lua +20 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/install.sh +10 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/make_summary.py +68 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/startup-summary.md +10 -0
- package/nvim/plugins/mini.nvim/colors/miniautumn.lua +55 -0
- package/nvim/plugins/mini.nvim/colors/minicyan.lua +95 -0
- package/nvim/plugins/mini.nvim/colors/minischeme.lua +95 -0
- package/nvim/plugins/mini.nvim/colors/minispring.lua +53 -0
- package/nvim/plugins/mini.nvim/colors/minisummer.lua +49 -0
- package/nvim/plugins/mini.nvim/colors/miniwinter.lua +51 -0
- package/nvim/plugins/mini.nvim/colors/randomhue.lua +16 -0
- package/nvim/plugins/mini.nvim/doc/mini-ai.txt +889 -0
- package/nvim/plugins/mini.nvim/doc/mini-align.txt +923 -0
- package/nvim/plugins/mini.nvim/doc/mini-animate.txt +937 -0
- package/nvim/plugins/mini.nvim/doc/mini-base16.txt +285 -0
- package/nvim/plugins/mini.nvim/doc/mini-basics.txt +359 -0
- package/nvim/plugins/mini.nvim/doc/mini-bracketed.txt +622 -0
- package/nvim/plugins/mini.nvim/doc/mini-bufremove.txt +123 -0
- package/nvim/plugins/mini.nvim/doc/mini-clue.txt +760 -0
- package/nvim/plugins/mini.nvim/doc/mini-cmdline.txt +392 -0
- package/nvim/plugins/mini.nvim/doc/mini-colors.txt +880 -0
- package/nvim/plugins/mini.nvim/doc/mini-comment.txt +230 -0
- package/nvim/plugins/mini.nvim/doc/mini-completion.txt +477 -0
- package/nvim/plugins/mini.nvim/doc/mini-cursorword.txt +105 -0
- package/nvim/plugins/mini.nvim/doc/mini-deps.txt +590 -0
- package/nvim/plugins/mini.nvim/doc/mini-diff.txt +661 -0
- package/nvim/plugins/mini.nvim/doc/mini-doc.txt +434 -0
- package/nvim/plugins/mini.nvim/doc/mini-extra.txt +856 -0
- package/nvim/plugins/mini.nvim/doc/mini-files.txt +1018 -0
- package/nvim/plugins/mini.nvim/doc/mini-fuzzy.txt +160 -0
- package/nvim/plugins/mini.nvim/doc/mini-git.txt +425 -0
- package/nvim/plugins/mini.nvim/doc/mini-hipatterns.txt +489 -0
- package/nvim/plugins/mini.nvim/doc/mini-hues.txt +420 -0
- package/nvim/plugins/mini.nvim/doc/mini-icons.txt +508 -0
- package/nvim/plugins/mini.nvim/doc/mini-indentscope.txt +485 -0
- package/nvim/plugins/mini.nvim/doc/mini-input.txt +932 -0
- package/nvim/plugins/mini.nvim/doc/mini-jump.txt +202 -0
- package/nvim/plugins/mini.nvim/doc/mini-jump2d.txt +525 -0
- package/nvim/plugins/mini.nvim/doc/mini-keymap.txt +449 -0
- package/nvim/plugins/mini.nvim/doc/mini-map.txt +717 -0
- package/nvim/plugins/mini.nvim/doc/mini-misc.txt +431 -0
- package/nvim/plugins/mini.nvim/doc/mini-move.txt +181 -0
- package/nvim/plugins/mini.nvim/doc/mini-notify.txt +434 -0
- package/nvim/plugins/mini.nvim/doc/mini-nvim.txt +431 -0
- package/nvim/plugins/mini.nvim/doc/mini-operators.txt +472 -0
- package/nvim/plugins/mini.nvim/doc/mini-pairs.txt +346 -0
- package/nvim/plugins/mini.nvim/doc/mini-pick.txt +1535 -0
- package/nvim/plugins/mini.nvim/doc/mini-sessions.txt +239 -0
- package/nvim/plugins/mini.nvim/doc/mini-snippets.txt +1291 -0
- package/nvim/plugins/mini.nvim/doc/mini-splitjoin.txt +536 -0
- package/nvim/plugins/mini.nvim/doc/mini-starter.txt +618 -0
- package/nvim/plugins/mini.nvim/doc/mini-statusline.txt +361 -0
- package/nvim/plugins/mini.nvim/doc/mini-surround.txt +863 -0
- package/nvim/plugins/mini.nvim/doc/mini-tabline.txt +151 -0
- package/nvim/plugins/mini.nvim/doc/mini-test.txt +966 -0
- package/nvim/plugins/mini.nvim/doc/mini-trailspace.txt +91 -0
- package/nvim/plugins/mini.nvim/doc/mini-visits.txt +937 -0
- package/nvim/plugins/mini.nvim/logo.png +0 -0
- package/nvim/plugins/mini.nvim/lua/mini/ai.lua +2244 -0
- package/nvim/plugins/mini.nvim/lua/mini/align.lua +2076 -0
- package/nvim/plugins/mini.nvim/lua/mini/animate.lua +2127 -0
- package/nvim/plugins/mini.nvim/lua/mini/base16.lua +1752 -0
- package/nvim/plugins/mini.nvim/lua/mini/basics.lua +772 -0
- package/nvim/plugins/mini.nvim/lua/mini/bracketed.lua +2013 -0
- package/nvim/plugins/mini.nvim/lua/mini/bufremove.lua +283 -0
- package/nvim/plugins/mini.nvim/lua/mini/clue.lua +2096 -0
- package/nvim/plugins/mini.nvim/lua/mini/cmdline.lua +1182 -0
- package/nvim/plugins/mini.nvim/lua/mini/colors.lua +2483 -0
- package/nvim/plugins/mini.nvim/lua/mini/comment.lua +586 -0
- package/nvim/plugins/mini.nvim/lua/mini/completion.lua +2094 -0
- package/nvim/plugins/mini.nvim/lua/mini/cursorword.lua +311 -0
- package/nvim/plugins/mini.nvim/lua/mini/deps.lua +1660 -0
- package/nvim/plugins/mini.nvim/lua/mini/diff.lua +1938 -0
- package/nvim/plugins/mini.nvim/lua/mini/doc.lua +1371 -0
- package/nvim/plugins/mini.nvim/lua/mini/extra.lua +2290 -0
- package/nvim/plugins/mini.nvim/lua/mini/files.lua +3145 -0
- package/nvim/plugins/mini.nvim/lua/mini/fuzzy.lua +356 -0
- package/nvim/plugins/mini.nvim/lua/mini/git.lua +1737 -0
- package/nvim/plugins/mini.nvim/lua/mini/hipatterns.lua +1042 -0
- package/nvim/plugins/mini.nvim/lua/mini/hues.lua +2088 -0
- package/nvim/plugins/mini.nvim/lua/mini/icons.lua +2254 -0
- package/nvim/plugins/mini.nvim/lua/mini/indentscope.lua +1158 -0
- package/nvim/plugins/mini.nvim/lua/mini/init.lua +427 -0
- package/nvim/plugins/mini.nvim/lua/mini/input.lua +2183 -0
- package/nvim/plugins/mini.nvim/lua/mini/jump.lua +609 -0
- package/nvim/plugins/mini.nvim/lua/mini/jump2d.lua +1244 -0
- package/nvim/plugins/mini.nvim/lua/mini/keymap.lua +880 -0
- package/nvim/plugins/mini.nvim/lua/mini/map.lua +1709 -0
- package/nvim/plugins/mini.nvim/lua/mini/misc.lua +969 -0
- package/nvim/plugins/mini.nvim/lua/mini/move.lua +509 -0
- package/nvim/plugins/mini.nvim/lua/mini/notify.lua +938 -0
- package/nvim/plugins/mini.nvim/lua/mini/operators.lua +1349 -0
- package/nvim/plugins/mini.nvim/lua/mini/pairs.lua +657 -0
- package/nvim/plugins/mini.nvim/lua/mini/pick.lua +3876 -0
- package/nvim/plugins/mini.nvim/lua/mini/sessions.lua +689 -0
- package/nvim/plugins/mini.nvim/lua/mini/snippets.lua +2828 -0
- package/nvim/plugins/mini.nvim/lua/mini/splitjoin.lua +1132 -0
- package/nvim/plugins/mini.nvim/lua/mini/starter.lua +1599 -0
- package/nvim/plugins/mini.nvim/lua/mini/statusline.lua +686 -0
- package/nvim/plugins/mini.nvim/lua/mini/surround.lua +2388 -0
- package/nvim/plugins/mini.nvim/lua/mini/tabline.lua +564 -0
- package/nvim/plugins/mini.nvim/lua/mini/test.lua +2516 -0
- package/nvim/plugins/mini.nvim/lua/mini/trailspace.lua +215 -0
- package/nvim/plugins/mini.nvim/lua/mini/visits.lua +1577 -0
- package/nvim/plugins/mini.nvim/readmes/mini-ai.md +190 -0
- package/nvim/plugins/mini.nvim/readmes/mini-align.md +203 -0
- package/nvim/plugins/mini.nvim/readmes/mini-animate.md +214 -0
- package/nvim/plugins/mini.nvim/readmes/mini-base16.md +198 -0
- package/nvim/plugins/mini.nvim/readmes/mini-basics.md +184 -0
- package/nvim/plugins/mini.nvim/readmes/mini-bracketed.md +193 -0
- package/nvim/plugins/mini.nvim/readmes/mini-bufremove.md +139 -0
- package/nvim/plugins/mini.nvim/readmes/mini-clue.md +260 -0
- package/nvim/plugins/mini.nvim/readmes/mini-cmdline.md +183 -0
- package/nvim/plugins/mini.nvim/readmes/mini-colors.md +169 -0
- package/nvim/plugins/mini.nvim/readmes/mini-comment.md +183 -0
- package/nvim/plugins/mini.nvim/readmes/mini-completion.md +217 -0
- package/nvim/plugins/mini.nvim/readmes/mini-cursorword.md +137 -0
- package/nvim/plugins/mini.nvim/readmes/mini-deps.md +271 -0
- package/nvim/plugins/mini.nvim/readmes/mini-diff.md +289 -0
- package/nvim/plugins/mini.nvim/readmes/mini-doc.md +198 -0
- package/nvim/plugins/mini.nvim/readmes/mini-extra.md +158 -0
- package/nvim/plugins/mini.nvim/readmes/mini-files.md +247 -0
- package/nvim/plugins/mini.nvim/readmes/mini-fuzzy.md +134 -0
- package/nvim/plugins/mini.nvim/readmes/mini-git.md +168 -0
- package/nvim/plugins/mini.nvim/readmes/mini-hipatterns.md +176 -0
- package/nvim/plugins/mini.nvim/readmes/mini-hues.md +285 -0
- package/nvim/plugins/mini.nvim/readmes/mini-icons.md +183 -0
- package/nvim/plugins/mini.nvim/readmes/mini-indentscope.md +191 -0
- package/nvim/plugins/mini.nvim/readmes/mini-input.md +163 -0
- package/nvim/plugins/mini.nvim/readmes/mini-jump.md +161 -0
- package/nvim/plugins/mini.nvim/readmes/mini-jump2d.md +197 -0
- package/nvim/plugins/mini.nvim/readmes/mini-keymap.md +205 -0
- package/nvim/plugins/mini.nvim/readmes/mini-map.md +191 -0
- package/nvim/plugins/mini.nvim/readmes/mini-misc.md +145 -0
- package/nvim/plugins/mini.nvim/readmes/mini-move.md +163 -0
- package/nvim/plugins/mini.nvim/readmes/mini-notify.md +175 -0
- package/nvim/plugins/mini.nvim/readmes/mini-operators.md +193 -0
- package/nvim/plugins/mini.nvim/readmes/mini-pairs.md +158 -0
- package/nvim/plugins/mini.nvim/readmes/mini-pick.md +340 -0
- package/nvim/plugins/mini.nvim/readmes/mini-sessions.md +164 -0
- package/nvim/plugins/mini.nvim/readmes/mini-snippets.md +373 -0
- package/nvim/plugins/mini.nvim/readmes/mini-splitjoin.md +194 -0
- package/nvim/plugins/mini.nvim/readmes/mini-starter.md +176 -0
- package/nvim/plugins/mini.nvim/readmes/mini-statusline.md +155 -0
- package/nvim/plugins/mini.nvim/readmes/mini-surround.md +190 -0
- package/nvim/plugins/mini.nvim/readmes/mini-tabline.md +156 -0
- package/nvim/plugins/mini.nvim/readmes/mini-test.md +175 -0
- package/nvim/plugins/mini.nvim/readmes/mini-trailspace.md +137 -0
- package/nvim/plugins/mini.nvim/readmes/mini-visits.md +243 -0
- package/nvim/plugins/mini.nvim/scripts/dual_log.sh +13 -0
- package/nvim/plugins/mini.nvim/scripts/dual_push.sh +15 -0
- package/nvim/plugins/mini.nvim/scripts/dual_release.sh +102 -0
- package/nvim/plugins/mini.nvim/scripts/dual_sync.sh +115 -0
- package/nvim/plugins/mini.nvim/scripts/init-deps-example.lua +59 -0
- package/nvim/plugins/mini.nvim/scripts/lint-filename-length.sh +16 -0
- package/nvim/plugins/mini.nvim/scripts/lintcommit-ci.sh +18 -0
- package/nvim/plugins/mini.nvim/scripts/lintcommit.lua +393 -0
- package/nvim/plugins/mini.nvim/scripts/minidoc.lua +57 -0
- package/nvim/plugins/mini.nvim/scripts/minimal_init.lua +28 -0
- package/nvim/plugins/mini.nvim/scripts/minitest.lua +4 -0
- package/package.json +16 -0
- package/pyproject.toml +43 -0
- package/yazi/init.lua +12 -0
- package/yazi/keymap.toml +114 -0
- package/yazi/lesskey +5 -0
- package/yazi/plugins/bookmarks.yazi/main.lua +86 -0
- package/yazi/plugins/cd-git-root.yazi/main.lua +31 -0
- package/yazi/plugins/smart-enter.yazi/main.lua +11 -0
- package/yazi/theme.toml +26 -0
- package/yazi/yazi.toml +15 -0
- package/zsh/.zshrc +145 -0
- package/zsh/starship.toml +20 -0
- package/zsh/zsh-patina.toml +2 -0
|
@@ -0,0 +1,1132 @@
|
|
|
1
|
+
--- *mini.splitjoin* Split and join arguments
|
|
2
|
+
---
|
|
3
|
+
--- MIT License Copyright (c) 2023 Evgeni Chasnovski
|
|
4
|
+
|
|
5
|
+
--- Features:
|
|
6
|
+
--- - Mappings and Lua functions that modify arguments (regions inside brackets
|
|
7
|
+
--- between allowed separators) under cursor.
|
|
8
|
+
---
|
|
9
|
+
--- Supported actions:
|
|
10
|
+
--- - Toggle - split if arguments are on single line, join otherwise.
|
|
11
|
+
--- Main supported function of the module. See |MiniSplitjoin.toggle()|.
|
|
12
|
+
--- - Split - make every argument separator be on end of separate line.
|
|
13
|
+
--- See |MiniSplitjoin.split()|.
|
|
14
|
+
--- - Join - make all arguments be on single line.
|
|
15
|
+
--- See |MiniSplitjoin.join()|.
|
|
16
|
+
---
|
|
17
|
+
--- - Mappings are dot-repeatable in Normal mode and work in Visual mode.
|
|
18
|
+
---
|
|
19
|
+
--- - Customizable argument detection (see |MiniSplitjoin.config.detect|):
|
|
20
|
+
--- - Which brackets can contain arguments.
|
|
21
|
+
--- - Which strings can separate arguments.
|
|
22
|
+
--- - Which regions are excluded when looking for separators (like inside
|
|
23
|
+
--- nested brackets or quotes).
|
|
24
|
+
---
|
|
25
|
+
--- - Customizable pre and post hooks for both split and join. See `split` and
|
|
26
|
+
--- `join` in |MiniSplitjoin.config|. There are several built-in ones
|
|
27
|
+
--- in |MiniSplitjoin.gen_hook|.
|
|
28
|
+
---
|
|
29
|
+
--- - Works inside comments by using modified notion of indent.
|
|
30
|
+
--- See |MiniSplitjoin.get_indent_part()|.
|
|
31
|
+
---
|
|
32
|
+
--- - Provides low-level Lua functions for split and join at positions.
|
|
33
|
+
--- See |MiniSplitjoin.split_at()| and |MiniSplitjoin.join_at()|.
|
|
34
|
+
---
|
|
35
|
+
--- Notes:
|
|
36
|
+
--- - Search for arguments is done using Lua patterns (regex-like approach).
|
|
37
|
+
--- Certain amount of false positives is to be expected.
|
|
38
|
+
---
|
|
39
|
+
--- - This module is mostly designed around |MiniSplitjoin.toggle()|. If target
|
|
40
|
+
--- split positions are on different lines, join first and then split.
|
|
41
|
+
---
|
|
42
|
+
--- - Actions can be done on Visual mode selection, which mostly present as
|
|
43
|
+
--- a safety route in case of incorrect detection of initial region.
|
|
44
|
+
--- It uses |MiniSplitjoin.get_visual_region()| which treats selection as full
|
|
45
|
+
--- brackets (include brackets in selection).
|
|
46
|
+
---
|
|
47
|
+
--- # Setup ~
|
|
48
|
+
---
|
|
49
|
+
--- This module needs a setup with `require('mini.splitjoin').setup({})` (replace
|
|
50
|
+
--- `{}` with your `config` table). It will create global Lua table `MiniSplitjoin`
|
|
51
|
+
--- which you can use for scripting or manually (with `:lua MiniSplitjoin.*`).
|
|
52
|
+
---
|
|
53
|
+
--- See |MiniSplitjoin.config| for available config settings.
|
|
54
|
+
---
|
|
55
|
+
--- You can override runtime config settings (like action hooks) locally to
|
|
56
|
+
--- buffer inside `vim.b.minisplitjoin_config` which should have same structure
|
|
57
|
+
--- as `MiniSplitjoin.config`. See |mini.nvim-buffer-local-config| for more details.
|
|
58
|
+
---
|
|
59
|
+
--- # Comparisons ~
|
|
60
|
+
---
|
|
61
|
+
--- - [FooSoft/vim-argwrap](https://github.com/FooSoft/vim-argwrap):
|
|
62
|
+
--- - Mostly has the same design as this module.
|
|
63
|
+
--- - Doesn't work inside comments, while this module does.
|
|
64
|
+
--- - Has more built-in ways to control split and join, while this module
|
|
65
|
+
--- intentionally provides only handful.
|
|
66
|
+
--- - [AndrewRadev/splitjoin.vim](https://github.com/AndrewRadev/splitjoin.vim):
|
|
67
|
+
--- - More oriented towards language-depended transformations, while this
|
|
68
|
+
--- module intntionally deals with more generic text-related functionality.
|
|
69
|
+
--- - [Wansmer/treesj](https://github.com/Wansmer/treesj):
|
|
70
|
+
--- - Operates based on tree-sitter nodes. This is more accurate in
|
|
71
|
+
--- some edge cases, but REQUIRES tree-sitter parser.
|
|
72
|
+
--- - Doesn't work inside comments or strings.
|
|
73
|
+
---
|
|
74
|
+
--- # Disabling ~
|
|
75
|
+
---
|
|
76
|
+
--- To disable, set `g:minisplitjoin_disable` (globally) or `b:minisplitjoin_disable`
|
|
77
|
+
--- (for a buffer) to `v:true`. Considering high number of different scenarios
|
|
78
|
+
--- and customization intentions, writing exact rules for disabling module's
|
|
79
|
+
--- functionality is left to user. See |mini.nvim-disabling-recipes| for common
|
|
80
|
+
--- recipes.
|
|
81
|
+
---@tag MiniSplitjoin
|
|
82
|
+
|
|
83
|
+
--- POSITION ~
|
|
84
|
+
--- Table with fields <line> and <col> containing line and column numbers
|
|
85
|
+
--- respectively. Both are 1-indexed. Example: `{ line = 2, col = 1 }`.
|
|
86
|
+
---
|
|
87
|
+
--- REGION ~
|
|
88
|
+
--- Table representing region in a buffer. Fields: <from> and <to> for
|
|
89
|
+
--- inclusive start and end positions. Example: >lua
|
|
90
|
+
---
|
|
91
|
+
--- { from = { line = 1, col = 1 }, to = { line = 2, col = 1 } }
|
|
92
|
+
--- <
|
|
93
|
+
---@tag MiniSplitjoin-glossary
|
|
94
|
+
|
|
95
|
+
---@alias __splitjoin_options table|nil Options. Has structure from |MiniSplitjoin.config|
|
|
96
|
+
--- inheriting its default values.
|
|
97
|
+
---
|
|
98
|
+
--- Following extra optional fields are allowed:
|
|
99
|
+
--- - <position> `(table)` - position at which to find smallest bracket region.
|
|
100
|
+
--- See |MiniSplitjoin-glossary| for the structure.
|
|
101
|
+
--- Default: cursor position.
|
|
102
|
+
--- - <region> `(table)` - region at which to perform action. Assumes inclusive
|
|
103
|
+
--- both start at left bracket and end at right bracket.
|
|
104
|
+
--- See |MiniSplitjoin-glossary| for the structure.
|
|
105
|
+
--- Default: `nil` to automatically detect region.
|
|
106
|
+
---@alias __splitjoin_hook_brackets - <brackets> `(table)` - array of bracket patterns indicating on which
|
|
107
|
+
--- brackets action should be made. Has same structure as `brackets`
|
|
108
|
+
--- in |MiniSplitjoin.config.detect|.
|
|
109
|
+
--- Default: `MiniSplitjoin.config.detect.brackets`.
|
|
110
|
+
|
|
111
|
+
---@diagnostic disable:undefined-field
|
|
112
|
+
---@diagnostic disable:discard-returns
|
|
113
|
+
---@diagnostic disable:unused-local
|
|
114
|
+
|
|
115
|
+
-- Module definition ==========================================================
|
|
116
|
+
local MiniSplitjoin = {}
|
|
117
|
+
local H = {}
|
|
118
|
+
|
|
119
|
+
--- Module setup
|
|
120
|
+
---
|
|
121
|
+
---@param config table|nil Module config table. See |MiniSplitjoin.config|.
|
|
122
|
+
---
|
|
123
|
+
---@usage >lua
|
|
124
|
+
--- require('mini.splitjoin').setup() -- use default config
|
|
125
|
+
--- -- OR
|
|
126
|
+
--- require('mini.splitjoin').setup({}) -- replace {} with your config table
|
|
127
|
+
--- <
|
|
128
|
+
MiniSplitjoin.setup = function(config)
|
|
129
|
+
-- TODO: Remove after Neovim=0.9 support is dropped
|
|
130
|
+
if vim.fn.has('nvim-0.10') == 0 then
|
|
131
|
+
vim.notify(
|
|
132
|
+
'(mini.splitjoin) Neovim<0.10 is soft deprecated (module works but is not supported).'
|
|
133
|
+
.. " It will be deprecated after the next 'mini.nvim' release (module might not work)."
|
|
134
|
+
.. ' Please update your Neovim version.'
|
|
135
|
+
)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
-- Export module
|
|
139
|
+
_G.MiniSplitjoin = MiniSplitjoin
|
|
140
|
+
|
|
141
|
+
-- Setup config
|
|
142
|
+
config = H.setup_config(config)
|
|
143
|
+
|
|
144
|
+
-- Apply config
|
|
145
|
+
H.apply_config(config)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
--- Defaults ~
|
|
149
|
+
---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)
|
|
150
|
+
---@text # Detection ~
|
|
151
|
+
--- *MiniSplitjoin.config.detect*
|
|
152
|
+
---
|
|
153
|
+
--- The table at `config.detect` controls how arguments are detected using Lua
|
|
154
|
+
--- patterns. General idea is to convert whole buffer into a single line,
|
|
155
|
+
--- perform string search, and convert results back into 2d positions.
|
|
156
|
+
---
|
|
157
|
+
--- Example configuration: >lua
|
|
158
|
+
---
|
|
159
|
+
--- require('mini.splitjoin').setup({
|
|
160
|
+
--- detect = {
|
|
161
|
+
--- -- Detect only inside balanced parenthesis
|
|
162
|
+
--- brackets = { '%b()' },
|
|
163
|
+
---
|
|
164
|
+
--- -- Allow both `,` and `;` to separate arguments
|
|
165
|
+
--- separator = '[,;]',
|
|
166
|
+
---
|
|
167
|
+
--- -- Make any separator define an argument
|
|
168
|
+
--- exclude_regions = {},
|
|
169
|
+
--- },
|
|
170
|
+
--- })
|
|
171
|
+
--- <
|
|
172
|
+
--- ## Outer brackets ~
|
|
173
|
+
---
|
|
174
|
+
--- `detect.brackets` is an array of Lua patterns used to find enclosing region.
|
|
175
|
+
--- It is done by traversing whole buffer to find the smallest region matching
|
|
176
|
+
--- any supplied pattern.
|
|
177
|
+
---
|
|
178
|
+
--- Default: `nil`, inferred as `{ '%b()', '%b[]', '%b{}' }`.
|
|
179
|
+
--- So an argument can be inside a balanced `()`, `[]`, or `{}`.
|
|
180
|
+
---
|
|
181
|
+
--- Example: `brackets = { '%b()' }` will search for arguments only inside
|
|
182
|
+
--- balanced `()`.
|
|
183
|
+
---
|
|
184
|
+
--- ## Separator ~
|
|
185
|
+
---
|
|
186
|
+
--- `detect.separator` is a single Lua pattern defining which strings should be
|
|
187
|
+
--- treated as argument separators.
|
|
188
|
+
---
|
|
189
|
+
--- Empty string in `detect.separator` will result in only surrounding brackets
|
|
190
|
+
--- used as separators.
|
|
191
|
+
---
|
|
192
|
+
--- Only end of pattern match will be used as split/join positions.
|
|
193
|
+
---
|
|
194
|
+
--- Default: `','`. So an argument can be separated only with comma.
|
|
195
|
+
---
|
|
196
|
+
--- Example: `separator = { '[,;]' }` will treat both `,` and `;` as separators.
|
|
197
|
+
---
|
|
198
|
+
--- ## Excluded regions ~
|
|
199
|
+
---
|
|
200
|
+
--- `detect.exclude_regions` is an array of Lua patterns for sub-regions from which
|
|
201
|
+
--- to exclude separators. Enables correct detection in case of nested brackets
|
|
202
|
+
--- and quotes.
|
|
203
|
+
---
|
|
204
|
+
--- Default: `nil`; inferred as `{ '%b()', '%b[]', '%b{}', '%b""', "%b''" }`.
|
|
205
|
+
--- So a separator CAN NOT be inside a balanced `()`, `[]`, `{}` (representing
|
|
206
|
+
--- nested argument regions) or `""`, `''` (representing strings).
|
|
207
|
+
---
|
|
208
|
+
--- Example: `exclude_regions = {}` will not exclude any regions. So in case of
|
|
209
|
+
--- `f(a, { b, c })` it will detect both commas as argument separators.
|
|
210
|
+
---
|
|
211
|
+
--- # Hooks ~
|
|
212
|
+
---
|
|
213
|
+
--- `split.hooks_pre`, `split.hooks_post`, `join.hooks_pre`, and `join.hooks_post`
|
|
214
|
+
--- are arrays of hook functions. If empty (default) no hook is applied.
|
|
215
|
+
---
|
|
216
|
+
--- Hooks should take and return array of positions. See |MiniSplitjoin-glossary|.
|
|
217
|
+
---
|
|
218
|
+
--- They can be used to tweak actions:
|
|
219
|
+
---
|
|
220
|
+
--- - Pre-hooks are called before action. Each is applied on the output of
|
|
221
|
+
--- previous one. Input of first hook are detected split/join positions.
|
|
222
|
+
--- Output of last one is actually used to perform split/join.
|
|
223
|
+
---
|
|
224
|
+
--- - Post-hooks are called after action. Each is applied on the output of
|
|
225
|
+
--- previous one. Input of first hook are split/join positions from actual
|
|
226
|
+
--- action plus its region's right end as last position (for easier hook code).
|
|
227
|
+
--- Output of last one is used as action return value.
|
|
228
|
+
---
|
|
229
|
+
--- For more specific details see |MiniSplitjoin.split()| and |MiniSplitjoin.join()|.
|
|
230
|
+
---
|
|
231
|
+
--- See |MiniSplitjoin.gen_hook| for generating common hooks with examples.
|
|
232
|
+
MiniSplitjoin.config = {
|
|
233
|
+
-- Module mappings. Use `''` (empty string) to disable one.
|
|
234
|
+
-- Created for both Normal and Visual modes.
|
|
235
|
+
mappings = {
|
|
236
|
+
toggle = 'gS',
|
|
237
|
+
split = '',
|
|
238
|
+
join = '',
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
-- Detection options: where split/join should be done
|
|
242
|
+
detect = {
|
|
243
|
+
-- Array of Lua patterns to detect region with arguments.
|
|
244
|
+
-- Default: { '%b()', '%b[]', '%b{}' }
|
|
245
|
+
brackets = nil,
|
|
246
|
+
|
|
247
|
+
-- String Lua pattern defining argument separator
|
|
248
|
+
separator = ',',
|
|
249
|
+
|
|
250
|
+
-- Array of Lua patterns for sub-regions to exclude separators from.
|
|
251
|
+
-- Enables correct detection in presence of nested brackets and quotes.
|
|
252
|
+
-- Default: { '%b()', '%b[]', '%b{}', '%b""', "%b''" }
|
|
253
|
+
exclude_regions = nil,
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
-- Split options
|
|
257
|
+
split = {
|
|
258
|
+
hooks_pre = {},
|
|
259
|
+
hooks_post = {},
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
-- Join options
|
|
263
|
+
join = {
|
|
264
|
+
hooks_pre = {},
|
|
265
|
+
hooks_post = {},
|
|
266
|
+
},
|
|
267
|
+
}
|
|
268
|
+
--minidoc_afterlines_end
|
|
269
|
+
|
|
270
|
+
--- Toggle arguments
|
|
271
|
+
---
|
|
272
|
+
--- Overview:
|
|
273
|
+
--- - Detect region at input position: either by using supplied `opts.region` or
|
|
274
|
+
--- by finding smallest bracketed region surrounding position.
|
|
275
|
+
--- See |MiniSplitjoin.config.detect| for more details.
|
|
276
|
+
--- - If region spans single line, use |MiniSplitjoin.split()| with found region.
|
|
277
|
+
--- Otherwise use |MiniSplitjoin.join()|.
|
|
278
|
+
---
|
|
279
|
+
---@param opts __splitjoin_options
|
|
280
|
+
---
|
|
281
|
+
---@return any Output of chosen `split()` or `join()` action.
|
|
282
|
+
MiniSplitjoin.toggle = function(opts)
|
|
283
|
+
if H.is_disabled() then return end
|
|
284
|
+
|
|
285
|
+
opts = H.get_opts(opts)
|
|
286
|
+
|
|
287
|
+
local region = opts.region or H.find_smallest_bracket_region(opts.position, opts.detect.brackets)
|
|
288
|
+
if region == nil then return end
|
|
289
|
+
|
|
290
|
+
opts.region = region
|
|
291
|
+
if region.from.line == region.to.line then
|
|
292
|
+
return MiniSplitjoin.split(opts)
|
|
293
|
+
else
|
|
294
|
+
return MiniSplitjoin.join(opts)
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
--- Split arguments
|
|
299
|
+
---
|
|
300
|
+
--- Overview:
|
|
301
|
+
--- - Detect region: either by using supplied `opts.region` or by finding smallest
|
|
302
|
+
--- bracketed region surrounding input position (cursor position by default).
|
|
303
|
+
--- See |MiniSplitjoin.config.detect| for more details.
|
|
304
|
+
---
|
|
305
|
+
--- - Find separator positions using `separator` and `exclude_regions` from `opts`.
|
|
306
|
+
--- Both brackets are treated as separators.
|
|
307
|
+
--- See |MiniSplitjoin.config.detect| for more details.
|
|
308
|
+
--- Note: stop if no separator positions are found.
|
|
309
|
+
---
|
|
310
|
+
--- - Modify separator positions to represent split positions. Last split position
|
|
311
|
+
--- (which is inferred from right bracket) is moved one column to left so that
|
|
312
|
+
--- right bracket would move on new line.
|
|
313
|
+
---
|
|
314
|
+
--- - Apply all hooks from `opts.split.hooks_pre`. Each is applied on the output of
|
|
315
|
+
--- previous one. Input of first hook is split positions from previous step.
|
|
316
|
+
--- Output of last one is used as split positions in next step.
|
|
317
|
+
---
|
|
318
|
+
--- - Split and update split positions with |MiniSplitjoin.split_at()|.
|
|
319
|
+
---
|
|
320
|
+
--- - Apply all hooks from `opts.split.hooks_post`. Each is applied on the output of
|
|
321
|
+
--- previous one. Input of first hook is split positions from previous step plus
|
|
322
|
+
--- region's right end (for easier hook code).
|
|
323
|
+
--- Output of last one is used as function return value.
|
|
324
|
+
---
|
|
325
|
+
--- Note:
|
|
326
|
+
--- - By design, it doesn't detect if argument SHOULD be split, so application
|
|
327
|
+
--- on arguments spanning multiple lines can lead to undesirable result.
|
|
328
|
+
---
|
|
329
|
+
---@param opts __splitjoin_options
|
|
330
|
+
---
|
|
331
|
+
---@return any Output of last `opts.split.hooks_post` or `nil` if no split positions
|
|
332
|
+
--- found. Default: return value of |MiniSplitjoin.split_at()| application.
|
|
333
|
+
MiniSplitjoin.split = function(opts)
|
|
334
|
+
if H.is_disabled() then return end
|
|
335
|
+
|
|
336
|
+
opts = H.get_opts(opts)
|
|
337
|
+
|
|
338
|
+
local region = opts.region or H.find_smallest_bracket_region(opts.position, opts.detect.brackets)
|
|
339
|
+
if region == nil then return nil end
|
|
340
|
+
|
|
341
|
+
local positions = H.find_split_positions(region, opts.detect.separator, opts.detect.exclude_regions)
|
|
342
|
+
if #positions == 0 then return nil end
|
|
343
|
+
|
|
344
|
+
-- Call pre-hooks
|
|
345
|
+
for _, hook in ipairs(opts.split.hooks_pre) do
|
|
346
|
+
positions = hook(positions)
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
-- Split at positions
|
|
350
|
+
local split_positions = MiniSplitjoin.split_at(positions)
|
|
351
|
+
|
|
352
|
+
-- Call post-hooks to tweak splits. Add right bracket for easier hook code.
|
|
353
|
+
local last = split_positions[#split_positions]
|
|
354
|
+
local last_next_line = vim.fn.getline(last.line + 1)
|
|
355
|
+
local new_col = MiniSplitjoin.get_indent_part(last_next_line):len() + 1
|
|
356
|
+
table.insert(split_positions, { line = last.line + 1, col = new_col })
|
|
357
|
+
|
|
358
|
+
for _, hook in ipairs(opts.split.hooks_post) do
|
|
359
|
+
split_positions = hook(split_positions)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
return split_positions
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
--- Join arguments
|
|
366
|
+
---
|
|
367
|
+
--- Overview:
|
|
368
|
+
--- - Detect region: either by using supplied `opts.region` or by finding smallest
|
|
369
|
+
--- bracketed region surrounding input position (cursor position by default).
|
|
370
|
+
--- See |MiniSplitjoin.config.detect| for more details.
|
|
371
|
+
---
|
|
372
|
+
--- - Compute join positions to be line ends of all but last region lines.
|
|
373
|
+
--- Note: stop if no join positions are found.
|
|
374
|
+
---
|
|
375
|
+
--- - Apply all hooks from `opts.join.hooks_pre`. Each is applied on the output
|
|
376
|
+
--- of previous one. Input of first hook is join positions from previous step.
|
|
377
|
+
--- Output of last one is used as join positions in next step.
|
|
378
|
+
---
|
|
379
|
+
--- - Join and update join positions with |MiniSplitjoin.join_at()|.
|
|
380
|
+
---
|
|
381
|
+
--- - Apply all hooks from `opts.join.hooks_post`. Each is applied on the output
|
|
382
|
+
--- of previous one. Input of first hook is join positions from previous step
|
|
383
|
+
--- plus region's right end for easier hook code.
|
|
384
|
+
--- Output of last one is used as function return value.
|
|
385
|
+
---
|
|
386
|
+
---@param opts __splitjoin_options
|
|
387
|
+
---
|
|
388
|
+
---@return any Output of last `opts.split.hooks_post` or `nil` of no join positions
|
|
389
|
+
--- found. Default: return value of |MiniSplitjoin.join_at()| application.
|
|
390
|
+
MiniSplitjoin.join = function(opts)
|
|
391
|
+
if H.is_disabled() then return end
|
|
392
|
+
|
|
393
|
+
opts = H.get_opts(opts)
|
|
394
|
+
|
|
395
|
+
local region = opts.region or H.find_smallest_bracket_region(opts.position, opts.detect.brackets)
|
|
396
|
+
if region == nil then return nil end
|
|
397
|
+
|
|
398
|
+
local positions = H.find_join_positions(region)
|
|
399
|
+
if #positions == 0 then return nil end
|
|
400
|
+
|
|
401
|
+
-- Call pre-hooks
|
|
402
|
+
for _, hook in ipairs(opts.join.hooks_pre) do
|
|
403
|
+
positions = hook(positions)
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
-- Join at positions
|
|
407
|
+
local join_positions = MiniSplitjoin.join_at(positions)
|
|
408
|
+
|
|
409
|
+
-- Call post-hooks to tweak joins. Add right bracket for easier hook code.
|
|
410
|
+
local last = join_positions[#join_positions]
|
|
411
|
+
table.insert(join_positions, { line = last.line, col = last.col + 1 })
|
|
412
|
+
|
|
413
|
+
for _, hook in ipairs(opts.join.hooks_post) do
|
|
414
|
+
join_positions = hook(join_positions)
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
return join_positions
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
--- Generate common hooks
|
|
421
|
+
---
|
|
422
|
+
--- This is a table with function elements. Call to actually get hook.
|
|
423
|
+
---
|
|
424
|
+
--- All generated post-hooks return updated versions of their input reflecting
|
|
425
|
+
--- changes done inside hook.
|
|
426
|
+
---
|
|
427
|
+
--- Example for `lua` filetype (place it in `lua.lua` filetype plugin, |ftplugin|): >lua
|
|
428
|
+
---
|
|
429
|
+
--- local gen_hook = MiniSplitjoin.gen_hook
|
|
430
|
+
--- local curly = { brackets = { '%b{}' } }
|
|
431
|
+
---
|
|
432
|
+
--- -- Add trailing comma when splitting inside curly brackets
|
|
433
|
+
--- local add_comma_curly = gen_hook.add_trailing_separator(curly)
|
|
434
|
+
---
|
|
435
|
+
--- -- Delete trailing comma when joining inside curly brackets
|
|
436
|
+
--- local del_comma_curly = gen_hook.del_trailing_separator(curly)
|
|
437
|
+
---
|
|
438
|
+
--- -- Pad curly brackets with single space after join
|
|
439
|
+
--- local pad_curly = gen_hook.pad_brackets(curly)
|
|
440
|
+
---
|
|
441
|
+
--- -- Create buffer-local config
|
|
442
|
+
--- vim.b.minisplitjoin_config = {
|
|
443
|
+
--- split = { hooks_post = { add_comma_curly } },
|
|
444
|
+
--- join = { hooks_post = { del_comma_curly, pad_curly } },
|
|
445
|
+
--- }
|
|
446
|
+
--- <
|
|
447
|
+
MiniSplitjoin.gen_hook = {}
|
|
448
|
+
|
|
449
|
+
--- Generate hook to pad brackets
|
|
450
|
+
---
|
|
451
|
+
--- This is a join post-hook. Use in `join.hooks_post` of |MiniSplitjoin.config|.
|
|
452
|
+
---
|
|
453
|
+
---@param opts table|nil Options. Possible fields:
|
|
454
|
+
--- - <pad> `(string)` - pad to add after first and before last join positions.
|
|
455
|
+
--- Default: `' '` (single space).
|
|
456
|
+
--- __splitjoin_hook_brackets
|
|
457
|
+
---
|
|
458
|
+
---@return function A hook which adds inner pad to first and last join positions and
|
|
459
|
+
--- returns updated input join positions.
|
|
460
|
+
MiniSplitjoin.gen_hook.pad_brackets = function(opts)
|
|
461
|
+
opts = opts or {}
|
|
462
|
+
local pad = opts.pad or ' '
|
|
463
|
+
local brackets = opts.brackets or H.get_opts(opts).detect.brackets
|
|
464
|
+
local n_pad = pad:len()
|
|
465
|
+
|
|
466
|
+
return function(join_positions)
|
|
467
|
+
-- Act only on actual join
|
|
468
|
+
local n_pos = #join_positions
|
|
469
|
+
if n_pos == 0 or pad == '' then return join_positions end
|
|
470
|
+
|
|
471
|
+
-- Act only if brackets are matched. First join position should be exactly
|
|
472
|
+
-- on left bracket, last - just before right bracket.
|
|
473
|
+
local first, last = join_positions[1], join_positions[n_pos]
|
|
474
|
+
local brackets_matched = H.is_positions_inside_brackets(first, last, brackets)
|
|
475
|
+
if not brackets_matched then return join_positions end
|
|
476
|
+
|
|
477
|
+
-- Pad only in case of non-trivial join
|
|
478
|
+
if first.line == last.line and (last.col - first.col) <= 1 then return join_positions end
|
|
479
|
+
|
|
480
|
+
-- Add pad after left and before right edges
|
|
481
|
+
H.set_text(first.line - 1, last.col - 1, first.line - 1, last.col - 1, { pad })
|
|
482
|
+
H.set_text(first.line - 1, first.col, first.line - 1, first.col, { pad })
|
|
483
|
+
|
|
484
|
+
-- Update `join_positions` to reflect text change
|
|
485
|
+
-- - Account for left pad
|
|
486
|
+
for i = 2, n_pos do
|
|
487
|
+
join_positions[i].col = join_positions[i].col + n_pad
|
|
488
|
+
end
|
|
489
|
+
-- - Account for right pad
|
|
490
|
+
join_positions[n_pos].col = join_positions[n_pos].col + n_pad
|
|
491
|
+
|
|
492
|
+
return join_positions
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
--- Generate hook to add trailing separator
|
|
497
|
+
---
|
|
498
|
+
--- This is a split post-hook. Use in `split.hooks_post` of |MiniSplitjoin.config|.
|
|
499
|
+
---
|
|
500
|
+
---@param opts table|nil Options. Possible fields:
|
|
501
|
+
--- - <sep> `(string)` - separator to add before last split position.
|
|
502
|
+
--- Default: `','`.
|
|
503
|
+
--- __splitjoin_hook_brackets
|
|
504
|
+
---
|
|
505
|
+
---@return function A hook which adds separator before last split position and
|
|
506
|
+
--- returns updated input split positions.
|
|
507
|
+
MiniSplitjoin.gen_hook.add_trailing_separator = function(opts)
|
|
508
|
+
opts = opts or {}
|
|
509
|
+
local sep = opts.sep or ','
|
|
510
|
+
local brackets = opts.brackets or H.get_opts(opts).detect.brackets
|
|
511
|
+
|
|
512
|
+
return function(split_positions)
|
|
513
|
+
-- Add only in case there is at least one argument
|
|
514
|
+
local n_pos = #split_positions
|
|
515
|
+
if n_pos < 3 then return split_positions end
|
|
516
|
+
|
|
517
|
+
-- Act only if brackets are matched
|
|
518
|
+
local first, last = split_positions[1], split_positions[n_pos]
|
|
519
|
+
local brackets_matched = H.is_positions_inside_brackets(first, last, brackets)
|
|
520
|
+
if not brackets_matched then return split_positions end
|
|
521
|
+
|
|
522
|
+
-- Act only if there is no trailing separator already
|
|
523
|
+
local target_line = vim.fn.getline(last.line - 1)
|
|
524
|
+
local target_col = target_line:find(vim.pesc(sep) .. '$')
|
|
525
|
+
if target_col ~= nil then return split_positions end
|
|
526
|
+
|
|
527
|
+
-- Add trailing separator
|
|
528
|
+
local col = target_line:len()
|
|
529
|
+
H.set_text(last.line - 2, col, last.line - 2, col, { sep })
|
|
530
|
+
|
|
531
|
+
-- Don't update `split_positions`, as appending to line has no effect
|
|
532
|
+
return split_positions
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
--- Generate hook to delete trailing separator
|
|
537
|
+
---
|
|
538
|
+
--- This is a join post-hook. Use in `join.hooks_post` of |MiniSplitjoin.config|.
|
|
539
|
+
---
|
|
540
|
+
---@param opts table|nil Options. Possible fields:
|
|
541
|
+
--- - <sep> `(string)` - separator to remove before last join position.
|
|
542
|
+
--- Default: `','`.
|
|
543
|
+
--- __splitjoin_hook_brackets
|
|
544
|
+
---
|
|
545
|
+
---@return function A hook which adds separator before last split position and
|
|
546
|
+
--- returns updated input split positions.
|
|
547
|
+
MiniSplitjoin.gen_hook.del_trailing_separator = function(opts)
|
|
548
|
+
opts = opts or {}
|
|
549
|
+
local sep = opts.sep or ','
|
|
550
|
+
local brackets = opts.brackets or H.get_opts(opts).detect.brackets
|
|
551
|
+
local n_sep = sep:len()
|
|
552
|
+
|
|
553
|
+
return function(join_positions)
|
|
554
|
+
-- Act only on actual join
|
|
555
|
+
local n_pos = #join_positions
|
|
556
|
+
if n_pos == 0 then return join_positions end
|
|
557
|
+
|
|
558
|
+
-- Act only if brackets are matched
|
|
559
|
+
local first, last = join_positions[1], join_positions[n_pos]
|
|
560
|
+
local brackets_matched = H.is_positions_inside_brackets(first, last, brackets)
|
|
561
|
+
if not brackets_matched then return join_positions end
|
|
562
|
+
|
|
563
|
+
-- Act only if there is matched trailing separator
|
|
564
|
+
local target_line = vim.fn.getline(last.line):sub(1, last.col - 1)
|
|
565
|
+
local target_col = target_line:find(vim.pesc(sep) .. '%s*$')
|
|
566
|
+
if target_col == nil then return join_positions end
|
|
567
|
+
|
|
568
|
+
-- Remove trailing separator
|
|
569
|
+
H.set_text(last.line - 1, target_col - 1, last.line - 1, target_col - 1 + n_sep, {})
|
|
570
|
+
|
|
571
|
+
-- Update `join_positions` to reflect text change. Update last as it moved.
|
|
572
|
+
-- Do not update second to last because it didn't affect what was tracked.
|
|
573
|
+
join_positions[n_pos] = { line = last.line, col = last.col - n_sep }
|
|
574
|
+
|
|
575
|
+
return join_positions
|
|
576
|
+
end
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
--- Split at positions
|
|
580
|
+
---
|
|
581
|
+
--- Overview:
|
|
582
|
+
--- - For each position move all characters after it to next line and make it have
|
|
583
|
+
--- same indent as current one (see |MiniSplitjoin.get_indent_part()|).
|
|
584
|
+
--- Also remove trailing whitespace at position line.
|
|
585
|
+
---
|
|
586
|
+
--- - Increase indent of inner lines by a single pad: tab in case of |'noexpandtab'|
|
|
587
|
+
--- or |shiftwidth()| number of spaces otherwise.
|
|
588
|
+
---
|
|
589
|
+
--- Notes:
|
|
590
|
+
--- - Cursor is adjusted to follow text updates.
|
|
591
|
+
--- - Use output of this function to keep track of input positions.
|
|
592
|
+
---
|
|
593
|
+
---@param positions table Array of positions at which to perform split.
|
|
594
|
+
--- See |MiniSplitjoin-glossary| for their structure. Note: they don't have
|
|
595
|
+
--- to be ordered, but first and last ones will be used to infer lines for
|
|
596
|
+
--- which indent will be increased.
|
|
597
|
+
---
|
|
598
|
+
---@return table Array of new positions to where input `positions` were moved.
|
|
599
|
+
MiniSplitjoin.split_at = function(positions)
|
|
600
|
+
local n_pos = #positions
|
|
601
|
+
if n_pos == 0 then return {} end
|
|
602
|
+
|
|
603
|
+
-- Cache values that might change
|
|
604
|
+
local cursor_extmark = H.put_extmark_at_positions({ H.get_cursor_pos() })[1]
|
|
605
|
+
local input_extmarks = H.put_extmark_at_positions(positions)
|
|
606
|
+
|
|
607
|
+
-- Split at extmark positions
|
|
608
|
+
for i = 1, n_pos do
|
|
609
|
+
H.split_at_extmark(input_extmarks[i])
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
-- Increase indent of inner lines
|
|
613
|
+
local first_new_pos = H.get_extmark_pos(input_extmarks[1])
|
|
614
|
+
local last_new_pos = H.get_extmark_pos(input_extmarks[n_pos])
|
|
615
|
+
H.increase_indent(first_new_pos.line + 1, last_new_pos.line)
|
|
616
|
+
|
|
617
|
+
-- Put cursor back on tracked position
|
|
618
|
+
H.put_cursor_at_extmark(cursor_extmark)
|
|
619
|
+
|
|
620
|
+
-- Reconstruct input positions
|
|
621
|
+
local res = vim.tbl_map(H.get_extmark_pos, input_extmarks)
|
|
622
|
+
vim.api.nvim_buf_clear_namespace(0, H.ns_id, 0, -1)
|
|
623
|
+
return res
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
--- Join at positions
|
|
627
|
+
---
|
|
628
|
+
--- Overview:
|
|
629
|
+
--- - For each position join its line with the next line. Joining is done by
|
|
630
|
+
--- replacing trailing whitespace of the line and indent of its next line
|
|
631
|
+
--- (see |MiniSplitjoin.get_indent_part()|) with a pad string (single space except
|
|
632
|
+
--- empty string for first and last positions). To adjust this, use hooks
|
|
633
|
+
--- (for example, see |MiniSplitjoin.gen_hook.pad_brackets()|).
|
|
634
|
+
---
|
|
635
|
+
--- Notes:
|
|
636
|
+
--- - Cursor is adjusted to follow text updates.
|
|
637
|
+
--- - Use output of this function to keep track of input positions.
|
|
638
|
+
---
|
|
639
|
+
---@param positions table Array of positions at which to perform join.
|
|
640
|
+
--- See |MiniSplitjoin-glossary| for their structure. Note: they don't have
|
|
641
|
+
--- to be ordered, but first and last ones will have different pad string.
|
|
642
|
+
---
|
|
643
|
+
---@return table Array of new positions to where input `positions` were moved.
|
|
644
|
+
MiniSplitjoin.join_at = function(positions)
|
|
645
|
+
local n_pos = #positions
|
|
646
|
+
if n_pos == 0 then return {} end
|
|
647
|
+
|
|
648
|
+
-- Cache values that might change
|
|
649
|
+
local cursor_extmark = H.put_extmark_at_positions({ H.get_cursor_pos() })[1]
|
|
650
|
+
local input_extmarks = H.put_extmark_at_positions(positions)
|
|
651
|
+
|
|
652
|
+
-- Join at positions which are changing following extmarks
|
|
653
|
+
for i = 1, n_pos do
|
|
654
|
+
local cur_pad_string = (i == 1 or i == n_pos) and '' or ' '
|
|
655
|
+
H.join_at_extmark(input_extmarks[i], cur_pad_string)
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
-- Put cursor back on tracked position
|
|
659
|
+
H.put_cursor_at_extmark(cursor_extmark)
|
|
660
|
+
|
|
661
|
+
-- Reconstruct input positions
|
|
662
|
+
local res = vim.tbl_map(H.get_extmark_pos, input_extmarks)
|
|
663
|
+
vim.api.nvim_buf_clear_namespace(0, H.ns_id, 0, -1)
|
|
664
|
+
return res
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
--- Get previous visual region
|
|
668
|
+
---
|
|
669
|
+
--- Get previous visual selection using |'<| and |'>| marks in the format of
|
|
670
|
+
--- region (see |MiniSplitjoin-glossary|). Used in Visual mode mappings.
|
|
671
|
+
---
|
|
672
|
+
--- Note:
|
|
673
|
+
--- - Both marks are included in region.
|
|
674
|
+
--- - In linewise mode start is at column 1 and end is at line's last character.
|
|
675
|
+
---
|
|
676
|
+
---@return table A region. See |MiniSplitjoin-glossary| for exact structure.
|
|
677
|
+
MiniSplitjoin.get_visual_region = function()
|
|
678
|
+
local from_pos, to_pos = vim.fn.getpos("'<"), vim.fn.getpos("'>")
|
|
679
|
+
local from, to = { line = from_pos[2], col = from_pos[3] }, { line = to_pos[2], col = to_pos[3] }
|
|
680
|
+
-- Tweak for linewise Visual selection
|
|
681
|
+
if vim.fn.visualmode() == 'V' then
|
|
682
|
+
from.col, to.col = 1, vim.fn.col({ to.line, '$' }) - 1
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
return { from = from, to = to }
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
--- Get string's indent part
|
|
689
|
+
---
|
|
690
|
+
---@param line string String for which to compute indent.
|
|
691
|
+
---@param respect_comments boolean|nil Whether to respect comments as indent part.
|
|
692
|
+
--- Default: `true`.
|
|
693
|
+
---
|
|
694
|
+
---@return string Part of input representing line's indent. Can be empty string.
|
|
695
|
+
--- Use `string.len()` to compute indent in bytes.
|
|
696
|
+
MiniSplitjoin.get_indent_part = function(line, respect_comments)
|
|
697
|
+
if respect_comments == nil then respect_comments = true end
|
|
698
|
+
if not respect_comments then return line:match('^%s*') end
|
|
699
|
+
|
|
700
|
+
-- Make it respect various comment leaders
|
|
701
|
+
local comment_indent = H.get_comment_indent(line, H.get_comment_leaders())
|
|
702
|
+
if comment_indent ~= '' then return comment_indent end
|
|
703
|
+
|
|
704
|
+
return line:match('^%s*')
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
--- Operator for Normal mode mappings
|
|
708
|
+
---
|
|
709
|
+
--- Main function to be used in expression mappings. No need to use it
|
|
710
|
+
--- directly, everything is setup in |MiniSplitjoin.setup()|.
|
|
711
|
+
---
|
|
712
|
+
---@param task string Name of task.
|
|
713
|
+
MiniSplitjoin.operator = function(task)
|
|
714
|
+
local is_init_call = task == 'toggle' or task == 'split' or task == 'join'
|
|
715
|
+
if not is_init_call then
|
|
716
|
+
MiniSplitjoin[H.cache.operator_task]()
|
|
717
|
+
return ''
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
if H.is_disabled() then
|
|
721
|
+
-- Using `<Esc>` prevents moving cursor caused by current implementation
|
|
722
|
+
-- detail of adding `' '` inside expression mapping
|
|
723
|
+
return [[\<Esc>]]
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
H.cache.operator_task = task
|
|
727
|
+
vim.o.operatorfunc = 'v:lua.MiniSplitjoin.operator'
|
|
728
|
+
return 'g@'
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
-- Helper data ================================================================
|
|
732
|
+
-- Module default config
|
|
733
|
+
H.default_config = vim.deepcopy(MiniSplitjoin.config)
|
|
734
|
+
|
|
735
|
+
H.ns_id = vim.api.nvim_create_namespace('MiniSplitjoin')
|
|
736
|
+
|
|
737
|
+
H.cache = { operator_task = nil }
|
|
738
|
+
|
|
739
|
+
-- Helper functionality =======================================================
|
|
740
|
+
-- Settings -------------------------------------------------------------------
|
|
741
|
+
H.setup_config = function(config)
|
|
742
|
+
H.check_type('config', config, 'table', true)
|
|
743
|
+
config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})
|
|
744
|
+
|
|
745
|
+
H.check_type('mappings', config.mappings, 'table')
|
|
746
|
+
H.check_type('mappings.toggle', config.mappings.toggle, 'string', true)
|
|
747
|
+
H.check_type('mappings.split', config.mappings.split, 'string')
|
|
748
|
+
H.check_type('mappings.join', config.mappings.join, 'string', true)
|
|
749
|
+
|
|
750
|
+
H.check_type('detect', config.detect, 'table')
|
|
751
|
+
H.check_type('detect.brackets', config.detect.brackets, 'table', true)
|
|
752
|
+
H.check_type('detect.separator', config.detect.separator, 'string')
|
|
753
|
+
H.check_type('detect.exclude_regions', config.detect.exclude_regions, 'table', true)
|
|
754
|
+
|
|
755
|
+
H.check_type('split', config.split, 'table')
|
|
756
|
+
H.check_type('split.hooks_pre', config.split.hooks_pre, 'table')
|
|
757
|
+
H.check_type('split.hooks_post', config.split.hooks_post, 'table')
|
|
758
|
+
|
|
759
|
+
H.check_type('join', config.join, 'table')
|
|
760
|
+
H.check_type('join.hooks_pre', config.join.hooks_pre, 'table')
|
|
761
|
+
H.check_type('join.hooks_post', config.join.hooks_post, 'table')
|
|
762
|
+
|
|
763
|
+
return config
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
--stylua: ignore
|
|
767
|
+
H.apply_config = function(config)
|
|
768
|
+
MiniSplitjoin.config = config
|
|
769
|
+
|
|
770
|
+
-- Make mappings
|
|
771
|
+
local maps = config.mappings
|
|
772
|
+
|
|
773
|
+
H.map('n', maps.toggle, 'v:lua.MiniSplitjoin.operator("toggle") . " "', { expr = true, desc = 'Toggle arguments' })
|
|
774
|
+
H.map('n', maps.split, 'v:lua.MiniSplitjoin.operator("split") . " "', { expr = true, desc = 'Split arguments' })
|
|
775
|
+
H.map('n', maps.join, 'v:lua.MiniSplitjoin.operator("join") . " "', { expr = true, desc = 'Join arguments' })
|
|
776
|
+
|
|
777
|
+
H.map('x', maps.toggle, ':<C-u>lua MiniSplitjoin.toggle({ region = MiniSplitjoin.get_visual_region() })<CR>', { desc = 'Toggle arguments' })
|
|
778
|
+
H.map('x', maps.split, ':<C-u>lua MiniSplitjoin.split({ region = MiniSplitjoin.get_visual_region() })<CR>', { desc = 'Split arguments' })
|
|
779
|
+
H.map('x', maps.join, ':<C-u>lua MiniSplitjoin.join({ region = MiniSplitjoin.get_visual_region() })<CR>', { desc = 'Join arguments' })
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
H.is_disabled = function() return vim.g.minisplitjoin_disable == true or vim.b.minisplitjoin_disable == true end
|
|
783
|
+
|
|
784
|
+
H.get_config = function(config)
|
|
785
|
+
return vim.tbl_deep_extend('force', MiniSplitjoin.config, vim.b.minisplitjoin_config or {}, config or {})
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
H.get_opts = function(opts)
|
|
789
|
+
opts = opts or {}
|
|
790
|
+
|
|
791
|
+
-- Infer detect options. Can't use usual `vim.tbl_deep_extend()` because it
|
|
792
|
+
-- doesn't work properly on arrays
|
|
793
|
+
local default_detect = {
|
|
794
|
+
brackets = { '%b()', '%b[]', '%b{}' },
|
|
795
|
+
separator = ',',
|
|
796
|
+
exclude_regions = { '%b()', '%b[]', '%b{}', '%b""', "%b''" },
|
|
797
|
+
}
|
|
798
|
+
local config = H.get_config()
|
|
799
|
+
|
|
800
|
+
return {
|
|
801
|
+
position = opts.position or H.get_cursor_pos(),
|
|
802
|
+
region = opts.region,
|
|
803
|
+
-- Extend `detect` not deeply to avoid unwanted values from longer defaults
|
|
804
|
+
detect = vim.tbl_extend('force', default_detect, config.detect, opts.detect or {}),
|
|
805
|
+
split = vim.tbl_deep_extend('force', config.split, opts.split or {}),
|
|
806
|
+
join = vim.tbl_deep_extend('force', config.join, opts.join or {}),
|
|
807
|
+
}
|
|
808
|
+
end
|
|
809
|
+
|
|
810
|
+
-- Split ----------------------------------------------------------------------
|
|
811
|
+
H.split_at_extmark = function(extmark_id)
|
|
812
|
+
local pos = H.get_extmark_pos(extmark_id)
|
|
813
|
+
|
|
814
|
+
-- Split
|
|
815
|
+
H.set_text(pos.line - 1, pos.col, pos.line - 1, pos.col, { '', '' })
|
|
816
|
+
|
|
817
|
+
-- Remove trailing whitespace on split line
|
|
818
|
+
local split_line = vim.fn.getline(pos.line)
|
|
819
|
+
local start_of_trailspace = split_line:find('%s*$')
|
|
820
|
+
H.set_text(pos.line - 1, start_of_trailspace - 1, pos.line - 1, split_line:len(), {})
|
|
821
|
+
|
|
822
|
+
-- Adjust indent on new line
|
|
823
|
+
local cur_indent = MiniSplitjoin.get_indent_part(vim.fn.getline(pos.line + 1))
|
|
824
|
+
local new_indent = MiniSplitjoin.get_indent_part(split_line)
|
|
825
|
+
H.set_text(pos.line, 0, pos.line, cur_indent:len(), { new_indent })
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
H.find_split_positions = function(region, separator, exclude_regions)
|
|
829
|
+
local sep_positions = H.find_separator_positions(region, separator, exclude_regions)
|
|
830
|
+
local n_pos = #sep_positions
|
|
831
|
+
|
|
832
|
+
sep_positions[n_pos].col = sep_positions[n_pos].col - 1
|
|
833
|
+
return sep_positions
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
-- Join -----------------------------------------------------------------------
|
|
837
|
+
H.join_at_extmark = function(extmark_id, pad)
|
|
838
|
+
local line_num = H.get_extmark_pos(extmark_id).line
|
|
839
|
+
if vim.api.nvim_buf_line_count(0) <= line_num then return end
|
|
840
|
+
|
|
841
|
+
-- Join by replacing trailing whitespace of current line and indent of next
|
|
842
|
+
-- one with `pad`
|
|
843
|
+
local lines = vim.api.nvim_buf_get_lines(0, line_num - 1, line_num + 1, true)
|
|
844
|
+
local above_start_col = lines[1]:len() - lines[1]:match('%s*$'):len()
|
|
845
|
+
local below_end_col = MiniSplitjoin.get_indent_part(lines[2]):len()
|
|
846
|
+
|
|
847
|
+
H.set_text(line_num - 1, above_start_col, line_num, below_end_col, { pad })
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
H.find_join_positions = function(region, separator, exclude_regions)
|
|
851
|
+
local lines = vim.api.nvim_buf_get_lines(0, region.from.line - 1, region.to.line, true)
|
|
852
|
+
|
|
853
|
+
-- Join whole region into single line
|
|
854
|
+
local res = {}
|
|
855
|
+
local init_line = region.from.line - 1
|
|
856
|
+
for i = 1, #lines - 1 do
|
|
857
|
+
table.insert(res, { line = init_line + i, col = lines[i]:len() })
|
|
858
|
+
end
|
|
859
|
+
return res
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
-- Detect ---------------------------------------------------------------------
|
|
863
|
+
H.find_smallest_bracket_region = function(position, brackets)
|
|
864
|
+
local neigh = H.get_neighborhood()
|
|
865
|
+
local cur_offset = neigh.pos_to_offset(position)
|
|
866
|
+
|
|
867
|
+
local best_span = H.find_smallest_covering(neigh['1d'], cur_offset, brackets)
|
|
868
|
+
if best_span == nil then return nil end
|
|
869
|
+
|
|
870
|
+
return neigh.span_to_region(best_span)
|
|
871
|
+
end
|
|
872
|
+
|
|
873
|
+
H.find_smallest_covering = function(line, ref_offset, patterns)
|
|
874
|
+
local res, min_width = nil, math.huge
|
|
875
|
+
for _, pattern in ipairs(patterns) do
|
|
876
|
+
local cur_init = 0
|
|
877
|
+
local left, right = string.find(line, pattern, cur_init)
|
|
878
|
+
while left do
|
|
879
|
+
if left <= ref_offset and ref_offset <= right and (right - left) < min_width then
|
|
880
|
+
res, min_width = { from = left, to = right }, right - left
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
cur_init = left + 1
|
|
884
|
+
left, right = string.find(line, pattern, cur_init)
|
|
885
|
+
end
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
return res
|
|
889
|
+
end
|
|
890
|
+
|
|
891
|
+
H.find_separator_positions = function(region, separator, exclude_regions)
|
|
892
|
+
if separator == '' then return { region.from, region.to } end
|
|
893
|
+
|
|
894
|
+
local neigh = H.get_neighborhood()
|
|
895
|
+
local region_span = neigh.region_to_span(region)
|
|
896
|
+
local region_s = neigh['1d']:sub(region_span.from, region_span.to)
|
|
897
|
+
|
|
898
|
+
-- Match separator endings
|
|
899
|
+
local seps = {}
|
|
900
|
+
region_s:gsub(separator .. '()', function(r) table.insert(seps, r - 1) end)
|
|
901
|
+
|
|
902
|
+
-- Remove separators that are in excluded regions.
|
|
903
|
+
local inner_string, forbidden = region_s:sub(2, -2), {}
|
|
904
|
+
local add_to_forbidden = function(l, r) table.insert(forbidden, { from = l + 1, to = r }) end
|
|
905
|
+
|
|
906
|
+
for _, pat in ipairs(exclude_regions) do
|
|
907
|
+
inner_string:gsub('()' .. pat .. '()', add_to_forbidden)
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
-- - Also exclude trailing separator
|
|
911
|
+
inner_string:gsub('()' .. separator .. '%s*()$', add_to_forbidden)
|
|
912
|
+
|
|
913
|
+
local sub_offsets = vim.tbl_filter(function(x) return not H.is_offset_inside_spans(x, forbidden) end, seps)
|
|
914
|
+
|
|
915
|
+
-- Treat enclosing brackets as separators
|
|
916
|
+
if region_s:len() > 2 then
|
|
917
|
+
-- Use only last bracket in case of empty brackets
|
|
918
|
+
table.insert(sub_offsets, 1, 1)
|
|
919
|
+
end
|
|
920
|
+
table.insert(sub_offsets, region_s:len())
|
|
921
|
+
|
|
922
|
+
-- Convert offsets to positions
|
|
923
|
+
local start_offset = region_span.from
|
|
924
|
+
return vim.tbl_map(function(sub_off) return neigh.offset_to_pos(start_offset + sub_off - 1) end, sub_offsets)
|
|
925
|
+
end
|
|
926
|
+
|
|
927
|
+
H.is_offset_inside_spans = function(ref_point, spans)
|
|
928
|
+
for _, span in ipairs(spans) do
|
|
929
|
+
if span.from <= ref_point and ref_point <= span.to then return true end
|
|
930
|
+
end
|
|
931
|
+
return false
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
H.is_positions_inside_brackets = function(from_pos, to_pos, brackets)
|
|
935
|
+
local text_lines = vim.api.nvim_buf_get_text(0, from_pos.line - 1, from_pos.col - 1, to_pos.line - 1, to_pos.col, {})
|
|
936
|
+
local text = table.concat(text_lines, '\n')
|
|
937
|
+
|
|
938
|
+
for _, b in ipairs(brackets) do
|
|
939
|
+
if text:find('^' .. b .. '$') ~= nil then return true end
|
|
940
|
+
end
|
|
941
|
+
return false
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
H.is_char_at_position = function(position, char)
|
|
945
|
+
local present_char = vim.fn.getline(position.line):sub(position.col, position.col)
|
|
946
|
+
return present_char == char
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
-- Simplified version of "neighborhood" from 'mini.ai':
|
|
950
|
+
-- - Use whol buffer.
|
|
951
|
+
-- - No empty regions or spans.
|
|
952
|
+
--
|
|
953
|
+
-- NOTEs:
|
|
954
|
+
-- - `region = { from = { line = a, col = b }, to = { line = c, col = d } }`.
|
|
955
|
+
-- End-inclusive charwise selection. All `a`, `b`, `c`, `d` are 1-indexed.
|
|
956
|
+
-- - `offset` is the number between 1 to `neigh1d:len()`.
|
|
957
|
+
H.get_neighborhood = function()
|
|
958
|
+
local neigh2d = vim.api.nvim_buf_get_lines(0, 0, -1, false)
|
|
959
|
+
-- Append 'newline' character to distinguish between lines in 1d case
|
|
960
|
+
-- (crucial for handling empty lines)
|
|
961
|
+
for k, v in pairs(neigh2d) do
|
|
962
|
+
neigh2d[k] = v .. '\n'
|
|
963
|
+
end
|
|
964
|
+
local neigh1d = table.concat(neigh2d, '')
|
|
965
|
+
local n_lines = #neigh2d
|
|
966
|
+
|
|
967
|
+
-- Compute offsets for just before line starts
|
|
968
|
+
local line_offsets = {}
|
|
969
|
+
local cur_offset = 0
|
|
970
|
+
for i = 1, n_lines do
|
|
971
|
+
line_offsets[i] = cur_offset
|
|
972
|
+
cur_offset = cur_offset + neigh2d[i]:len()
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
-- Convert 2d buffer position to 1d offset
|
|
976
|
+
local pos_to_offset = function(pos) return line_offsets[pos.line] + pos.col end
|
|
977
|
+
|
|
978
|
+
-- Convert 1d offset to 2d buffer position
|
|
979
|
+
local offset_to_pos = function(offset)
|
|
980
|
+
for i = 1, n_lines - 1 do
|
|
981
|
+
if line_offsets[i] < offset and offset <= line_offsets[i + 1] then
|
|
982
|
+
return { line = i, col = offset - line_offsets[i] }
|
|
983
|
+
end
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
return { line = n_lines, col = offset - line_offsets[n_lines] }
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
-- Convert 2d region to 1d span
|
|
990
|
+
local region_to_span = function(region) return { from = pos_to_offset(region.from), to = pos_to_offset(region.to) } end
|
|
991
|
+
|
|
992
|
+
-- Convert 1d span to 2d region
|
|
993
|
+
local span_to_region = function(span) return { from = offset_to_pos(span.from), to = offset_to_pos(span.to) } end
|
|
994
|
+
|
|
995
|
+
return {
|
|
996
|
+
['1d'] = neigh1d,
|
|
997
|
+
['2d'] = neigh2d,
|
|
998
|
+
pos_to_offset = pos_to_offset,
|
|
999
|
+
offset_to_pos = offset_to_pos,
|
|
1000
|
+
region_to_span = region_to_span,
|
|
1001
|
+
span_to_region = span_to_region,
|
|
1002
|
+
}
|
|
1003
|
+
end
|
|
1004
|
+
|
|
1005
|
+
-- Extmarks -------------------------------------------------------------------
|
|
1006
|
+
H.put_extmark_at_positions = function(positions)
|
|
1007
|
+
return vim.tbl_map(
|
|
1008
|
+
function(pos) return vim.api.nvim_buf_set_extmark(0, H.ns_id, pos.line - 1, pos.col - 1, {}) end,
|
|
1009
|
+
positions
|
|
1010
|
+
)
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
H.get_extmark_pos = function(extmark_id)
|
|
1014
|
+
local res = vim.api.nvim_buf_get_extmark_by_id(0, H.ns_id, extmark_id, {})
|
|
1015
|
+
return { line = res[1] + 1, col = res[2] + 1 }
|
|
1016
|
+
end
|
|
1017
|
+
|
|
1018
|
+
H.get_cursor_pos = function()
|
|
1019
|
+
local cur_pos = vim.api.nvim_win_get_cursor(0)
|
|
1020
|
+
return { line = cur_pos[1], col = cur_pos[2] + 1 }
|
|
1021
|
+
end
|
|
1022
|
+
|
|
1023
|
+
H.put_cursor_at_extmark = function(id)
|
|
1024
|
+
local new_pos = vim.api.nvim_buf_get_extmark_by_id(0, H.ns_id, id, {})
|
|
1025
|
+
vim.api.nvim_win_set_cursor(0, { new_pos[1] + 1, new_pos[2] })
|
|
1026
|
+
vim.api.nvim_buf_del_extmark(0, H.ns_id, id)
|
|
1027
|
+
end
|
|
1028
|
+
|
|
1029
|
+
-- Indent ---------------------------------------------------------------------
|
|
1030
|
+
H.increase_indent = function(from_line, to_line)
|
|
1031
|
+
local lines = vim.api.nvim_buf_get_lines(0, from_line - 1, to_line, true)
|
|
1032
|
+
|
|
1033
|
+
-- Respect comment leaders only if all lines are commented
|
|
1034
|
+
local comment_leaders = H.get_comment_leaders()
|
|
1035
|
+
local respect_comments = H.is_comment_block(lines, comment_leaders)
|
|
1036
|
+
|
|
1037
|
+
-- Increase indent of all lines (end-inclusive)
|
|
1038
|
+
local pad = vim.bo.expandtab and string.rep(' ', vim.fn.shiftwidth()) or '\t'
|
|
1039
|
+
for i, l in ipairs(lines) do
|
|
1040
|
+
local n_indent = MiniSplitjoin.get_indent_part(l, respect_comments):len()
|
|
1041
|
+
|
|
1042
|
+
-- Don't increase indent of blank lines (possibly respecting comments)
|
|
1043
|
+
local cur_by_string = l:len() == n_indent and '' or pad
|
|
1044
|
+
|
|
1045
|
+
local line_num = from_line + i - 1
|
|
1046
|
+
H.set_text(line_num - 1, n_indent, line_num - 1, n_indent, { cur_by_string })
|
|
1047
|
+
end
|
|
1048
|
+
end
|
|
1049
|
+
|
|
1050
|
+
H.get_comment_indent = function(line, comment_leaders)
|
|
1051
|
+
local res = ''
|
|
1052
|
+
|
|
1053
|
+
for _, leader in ipairs(comment_leaders) do
|
|
1054
|
+
local cur_match = line:match('^%s*' .. vim.pesc(leader) .. '%s*')
|
|
1055
|
+
-- Use biggest match in case of several matches. Allows respecting "nested"
|
|
1056
|
+
-- comment leaders like "---" and "--".
|
|
1057
|
+
if type(cur_match) == 'string' and res:len() < cur_match:len() then res = cur_match end
|
|
1058
|
+
end
|
|
1059
|
+
|
|
1060
|
+
return res
|
|
1061
|
+
end
|
|
1062
|
+
|
|
1063
|
+
-- Comments -------------------------------------------------------------------
|
|
1064
|
+
H.get_comment_leaders = function()
|
|
1065
|
+
local res = {}
|
|
1066
|
+
|
|
1067
|
+
-- From 'commentstring'
|
|
1068
|
+
local main_leader = vim.split(vim.bo.commentstring, '%%s')[1]
|
|
1069
|
+
-- - Ensure there is no whitespace before or after
|
|
1070
|
+
table.insert(res, vim.trim(main_leader))
|
|
1071
|
+
|
|
1072
|
+
-- From 'comments'
|
|
1073
|
+
for _, comment_part in ipairs(vim.opt_local.comments:get()) do
|
|
1074
|
+
local prefix, suffix = comment_part:match('^(.*):(.*)$')
|
|
1075
|
+
|
|
1076
|
+
-- Control whitespace around suffix
|
|
1077
|
+
suffix = vim.trim(suffix)
|
|
1078
|
+
|
|
1079
|
+
if prefix:find('b') then
|
|
1080
|
+
-- Respect `b` flag (for blank) requiring space, tab or EOL after it
|
|
1081
|
+
table.insert(res, suffix .. ' ')
|
|
1082
|
+
table.insert(res, suffix .. '\t')
|
|
1083
|
+
elseif prefix:find('f') == nil then
|
|
1084
|
+
-- Add otherwise ignoring `f` flag (only first line should have it)
|
|
1085
|
+
table.insert(res, suffix)
|
|
1086
|
+
end
|
|
1087
|
+
end
|
|
1088
|
+
|
|
1089
|
+
return res
|
|
1090
|
+
end
|
|
1091
|
+
|
|
1092
|
+
H.is_comment_block = function(lines, comment_leaders)
|
|
1093
|
+
for _, l in ipairs(lines) do
|
|
1094
|
+
if not H.is_commented(l, comment_leaders) then return false end
|
|
1095
|
+
end
|
|
1096
|
+
return true
|
|
1097
|
+
end
|
|
1098
|
+
|
|
1099
|
+
H.is_commented = function(line, comment_leaders)
|
|
1100
|
+
for _, leader in ipairs(comment_leaders) do
|
|
1101
|
+
if line:find('^%s*' .. vim.pesc(leader) .. '%s*') ~= nil then return true end
|
|
1102
|
+
end
|
|
1103
|
+
return false
|
|
1104
|
+
end
|
|
1105
|
+
|
|
1106
|
+
-- Utilities ------------------------------------------------------------------
|
|
1107
|
+
H.error = function(msg) error('(mini.splitjoin) ' .. msg, 0) end
|
|
1108
|
+
|
|
1109
|
+
H.check_type = function(name, val, ref, allow_nil)
|
|
1110
|
+
if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end
|
|
1111
|
+
H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))
|
|
1112
|
+
end
|
|
1113
|
+
|
|
1114
|
+
H.map = function(mode, lhs, rhs, opts)
|
|
1115
|
+
if lhs == '' then return end
|
|
1116
|
+
opts = vim.tbl_deep_extend('force', { silent = true }, opts or {})
|
|
1117
|
+
vim.keymap.set(mode, lhs, rhs, opts)
|
|
1118
|
+
end
|
|
1119
|
+
|
|
1120
|
+
H.set_text = function(start_row, start_col, end_row, end_col, replacement)
|
|
1121
|
+
local ok = pcall(vim.api.nvim_buf_set_text, 0, start_row, start_col, end_row, end_col, replacement)
|
|
1122
|
+
if not ok or #replacement == 0 then return end
|
|
1123
|
+
|
|
1124
|
+
-- Fix cursor position if it was exactly on start position.
|
|
1125
|
+
-- See https://github.com/neovim/neovim/issues/22526.
|
|
1126
|
+
local cursor = vim.api.nvim_win_get_cursor(0)
|
|
1127
|
+
if (start_row + 1) == cursor[1] and start_col == cursor[2] then
|
|
1128
|
+
vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + replacement[1]:len() })
|
|
1129
|
+
end
|
|
1130
|
+
end
|
|
1131
|
+
|
|
1132
|
+
return MiniSplitjoin
|