mirror of
https://github.com/chenasraf/text-transform.nvim.git
synced 2026-05-18 01:48:57 +00:00
Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
335b3ad36d | ||
| 9e628239ab | |||
| d7dd1c4dd7 | |||
| 16069971e9 | |||
| 9c62c9cd9d | |||
| 33eecfffab | |||
| 701d373e7a | |||
| 1c8fa21578 | |||
|
|
1c39528e7c | ||
| 972a44cf1e | |||
| ecd4d6bbbc | |||
| ea38606a28 | |||
| 3362c3c4f1 | |||
| a9d3ffc2de | |||
| 168552b425 | |||
| 8e7fe74888 | |||
| 4bbba5d1b3 | |||
| eaf84d857d | |||
| 0cb9c1e4ee | |||
| 8de9125de1 | |||
| bb177a3360 | |||
| 67aef1de42 | |||
|
|
b44d58a533 | ||
| 6863e0e9a6 | |||
| 733f26fef6 | |||
| be9c119ee2 | |||
|
|
52f26035d2 | ||
| f83f2afafd | |||
| a775191122 | |||
| 3f684bbdc0 | |||
| 646dde56f2 | |||
| ba385b846b | |||
| 9393d81815 | |||
|
|
e376ac78fc | ||
| 2fa82f80d6 | |||
| ad84766691 | |||
| fbb89b1b44 | |||
|
|
5c0132fe95 | ||
| 657bda1478 | |||
|
|
b500db2686 | ||
| 1fd7e334bc | |||
| 7ef73f26d1 | |||
|
|
1f3fc3df09 | ||
| b31967dd32 | |||
| 6f1c92872e | |||
| 69542d7e1c | |||
| 6e409f0a44 | |||
| dc3d4e6379 | |||
| 4628b50340 | |||
| 500edc66e6 | |||
| 758d90b88f | |||
| a669a998f4 | |||
| c0a354ac79 | |||
| b536b832d9 | |||
| fc2de91ac4 | |||
| a53e0d6d64 | |||
| bbe802e0b2 | |||
| e6735cceeb | |||
| b4257a50fe | |||
|
|
ded86d9b0f | ||
|
|
7518df3364 | ||
|
|
8f980db340 | ||
|
|
7edc585d15 | ||
|
|
9cd27aba2b | ||
|
|
43cc07cde4 | ||
|
|
eb3a7ae843 | ||
|
|
5765e3d721 | ||
|
|
bcb5ee3704 | ||
|
|
09e4b0986a | ||
|
|
e4d1687ab2 | ||
|
|
d4ef5c0e8c | ||
|
|
17b3a79374 | ||
|
|
9c1dd7e0e6 | ||
|
|
f79799cd91 | ||
|
|
63c0b700f7 | ||
|
|
fe617cc2ad | ||
|
|
18ff322f83 | ||
|
|
20fcc6b49c | ||
|
|
b6401e841f | ||
|
|
79f9da2467 | ||
|
|
4bc66d375b | ||
|
|
baa38828e4 | ||
|
|
36651b5aec | ||
|
|
52b155f43f | ||
|
|
7f842fbfe3 | ||
|
|
11ecfb6cc1 |
@@ -8,3 +8,6 @@ trim_trailing_whitespace = true
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
|
||||
65
.github/workflows/develop.yml
vendored
65
.github/workflows/develop.yml
vendored
@@ -1,23 +1,24 @@
|
||||
name: Release
|
||||
name: Dev Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop]
|
||||
pull_request:
|
||||
branches: [develop]
|
||||
types: [opened, synchronize]
|
||||
|
||||
concurrency:
|
||||
group: github.head_ref
|
||||
cancel-in-progress: true
|
||||
# concurrency:
|
||||
# group: github.head_ref
|
||||
# cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
name: lint
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: JohnnyMorganz/stylua-action@v2
|
||||
- uses: JohnnyMorganz/stylua-action@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: latest
|
||||
@@ -27,7 +28,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
name: documentation
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -41,19 +42,53 @@ jobs:
|
||||
run: make documentation-ci
|
||||
|
||||
- name: check docs diff
|
||||
run: exit $(git status --porcelain doc | wc -l | tr -d " ")
|
||||
release:
|
||||
name: release
|
||||
if: ${{ github.ref == 'refs/heads/develop' }}
|
||||
permissions: write-all
|
||||
run: |
|
||||
git status doc
|
||||
ex=$(git status --porcelain doc | wc -l | tr -d " ")
|
||||
if [[ $ex -ne 0 ]]; then git diff doc; fi
|
||||
exit $ex
|
||||
|
||||
tests:
|
||||
needs:
|
||||
- lint
|
||||
- documentation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
timeout-minutes: 2
|
||||
strategy:
|
||||
matrix:
|
||||
neovim_version: ['v0.7.2', 'v0.8.3', 'v0.9.0', 'nightly']
|
||||
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- run: date +%F > todays-date
|
||||
|
||||
- name: restore cache for today's nightly.
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: _neovim
|
||||
key: ${{ runner.os }}-x64-${{ hashFiles('todays-date') }}
|
||||
|
||||
- name: setup neovim
|
||||
uses: rhysd/action-setup-vim@v1
|
||||
with:
|
||||
neovim: true
|
||||
version: ${{ matrix.neovim_version }}
|
||||
|
||||
- name: run tests
|
||||
run: make test-ci
|
||||
|
||||
release:
|
||||
name: dev-release
|
||||
if: ${{ github.ref == 'refs/heads/develop' }}
|
||||
permissions: write-all
|
||||
needs:
|
||||
- tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: google-github-actions/release-please-action@v4
|
||||
id: release
|
||||
with:
|
||||
release-type: simple
|
||||
|
||||
74
.github/workflows/main.yml
vendored
74
.github/workflows/main.yml
vendored
@@ -4,20 +4,21 @@ on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
types: [opened, synchronize]
|
||||
|
||||
concurrency:
|
||||
group: github.head_ref
|
||||
cancel-in-progress: true
|
||||
# concurrency:
|
||||
# group: github.head_ref
|
||||
# cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
name: lint
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: JohnnyMorganz/stylua-action@v2
|
||||
- uses: JohnnyMorganz/stylua-action@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: latest
|
||||
@@ -27,7 +28,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
name: documentation
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -41,50 +42,53 @@ jobs:
|
||||
run: make documentation-ci
|
||||
|
||||
- name: check docs diff
|
||||
run: exit $(git status --porcelain doc | wc -l | tr -d " ")
|
||||
run: |
|
||||
git status doc
|
||||
ex=$(git status --porcelain doc | wc -l | tr -d " ")
|
||||
if [[ $ex -ne 0 ]]; then git diff doc; fi
|
||||
exit $ex
|
||||
|
||||
# tests:
|
||||
# needs:
|
||||
# - lint
|
||||
# - documentation
|
||||
# runs-on: ubuntu-latest
|
||||
# timeout-minutes: 2
|
||||
# strategy:
|
||||
# matrix:
|
||||
# neovim_version: ['v0.7.2', 'v0.8.3', 'v0.9.0', 'nightly']
|
||||
tests:
|
||||
needs:
|
||||
- lint
|
||||
- documentation
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
strategy:
|
||||
matrix:
|
||||
neovim_version: ['v0.7.2', 'v0.8.3', 'v0.9.0', 'nightly']
|
||||
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# - run: date +%F > todays-date
|
||||
- run: date +%F > todays-date
|
||||
|
||||
# - name: restore cache for today's nightly.
|
||||
# uses: actions/cache@v3
|
||||
# with:
|
||||
# path: _neovim
|
||||
# key: ${{ runner.os }}-x64-${{ hashFiles('todays-date') }}
|
||||
- name: restore cache for today's nightly.
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: _neovim
|
||||
key: ${{ runner.os }}-x64-${{ hashFiles('todays-date') }}
|
||||
|
||||
# - name: setup neovim
|
||||
# uses: rhysd/action-setup-vim@v1
|
||||
# with:
|
||||
# neovim: true
|
||||
# version: ${{ matrix.neovim_version }}
|
||||
- name: setup neovim
|
||||
uses: rhysd/action-setup-vim@v1
|
||||
with:
|
||||
neovim: true
|
||||
version: ${{ matrix.neovim_version }}
|
||||
|
||||
# - name: run tests
|
||||
# run: make test-ci
|
||||
- name: run tests
|
||||
run: make test-ci
|
||||
|
||||
release:
|
||||
name: release
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
permissions: write-all
|
||||
needs:
|
||||
- lint
|
||||
- documentation
|
||||
- tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
- uses: google-github-actions/release-please-action@v4
|
||||
id: release
|
||||
with:
|
||||
release-type: simple
|
||||
|
||||
93
CHANGELOG.md
93
CHANGELOG.md
@@ -1,5 +1,98 @@
|
||||
# Changelog
|
||||
|
||||
## [0.9.1](https://github.com/chenasraf/text-transform.nvim/compare/v0.9.0...v0.9.1) (2024-07-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* normal mode transforms ([d7dd1c4](https://github.com/chenasraf/text-transform.nvim/commit/d7dd1c4dd7e4ccd2da1458e5fb9a6653ad4e5e17))
|
||||
|
||||
## [0.9.0](https://github.com/chenasraf/text-transform.nvim/compare/v0.8.0...v0.9.0) (2024-05-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* non-telescope popup ([bb177a3](https://github.com/chenasraf/text-transform.nvim/commit/bb177a3360372f3fd40c82da71a13f1db59d3d9e))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* commands ([eaf84d8](https://github.com/chenasraf/text-transform.nvim/commit/eaf84d857d860828cbb5af96887a24c2ab99f8e8))
|
||||
* error on select ([168552b](https://github.com/chenasraf/text-transform.nvim/commit/168552b4259672fe918b1f3baeed787548e8fd03))
|
||||
* range commands ([ecd4d6b](https://github.com/chenasraf/text-transform.nvim/commit/ecd4d6bbbcd45231f2e8ea00961f076ff56dd1e7))
|
||||
* sorter init ([ea38606](https://github.com/chenasraf/text-transform.nvim/commit/ea38606a28f2308a37b301ebb4c56e2bd584b459))
|
||||
|
||||
## [0.8.0](https://github.com/chenasraf/text-transform.nvim/compare/v0.7.0...v0.8.0) (2024-05-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow sorter selection in config ([6863e0e](https://github.com/chenasraf/text-transform.nvim/commit/6863e0e9a66b5592fbba2aea7a07760465844cf7))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* frequency sort ([733f26f](https://github.com/chenasraf/text-transform.nvim/commit/733f26fef61b050ae8f62582e3f9c03268f8e835))
|
||||
* user commands ([be9c119](https://github.com/chenasraf/text-transform.nvim/commit/be9c119ee23f1e93a5bd537c01f55e11d2607180))
|
||||
|
||||
## [0.7.0](https://github.com/chenasraf/text-transform.nvim/compare/v0.6.0...v0.7.0) (2024-05-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* sort telescope by usage frequency ([f83f2af](https://github.com/chenasraf/text-transform.nvim/commit/f83f2afafdfbbcb986ca1c6d3db062cd3b964c62))
|
||||
|
||||
## [0.6.0](https://github.com/chenasraf/text-transform.nvim/compare/v0.5.1...v0.6.0) (2024-05-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* enable/disable specific replacers ([fbb89b1](https://github.com/chenasraf/text-transform.nvim/commit/fbb89b1b44dfb9b57cd241b7c574665cce7dab10))
|
||||
|
||||
## [0.5.1](https://github.com/chenasraf/text-transform.nvim/compare/v0.5.0...v0.5.1) (2024-04-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* exports ([657bda1](https://github.com/chenasraf/text-transform.nvim/commit/657bda14789b907911157c4f34e8a088c1e00d15))
|
||||
|
||||
## [0.5.0](https://github.com/chenasraf/text-transform.nvim/compare/v0.4.0...v0.5.0) (2024-04-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add commands ([500edc6](https://github.com/chenasraf/text-transform.nvim/commit/500edc66e6ac0a649108749ad290f2a370cf4219))
|
||||
* add telescope command ([6e409f0](https://github.com/chenasraf/text-transform.nvim/commit/6e409f0a44e50b3ef65f426e36b7824ee2d95d7a))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* precommit ([a669a99](https://github.com/chenasraf/text-transform.nvim/commit/a669a998f47de6c33e9667d40ce3a219d60af69b))
|
||||
* telescope ([7ef73f2](https://github.com/chenasraf/text-transform.nvim/commit/7ef73f26d13f72454d0388bdca4541f7f4aa78e2))
|
||||
* telescope command ([69542d7](https://github.com/chenasraf/text-transform.nvim/commit/69542d7e1c6c88832611fb3c0f1d46102c133bd1))
|
||||
* uppercase logic ([a669a99](https://github.com/chenasraf/text-transform.nvim/commit/a669a998f47de6c33e9667d40ce3a219d60af69b))
|
||||
* word break/transform ([a53e0d6](https://github.com/chenasraf/text-transform.nvim/commit/a53e0d6d64051d5fea6d102529c403e4cbd0cce2))
|
||||
|
||||
## [0.4.0](https://github.com/chenasraf/text-transform.nvim/compare/v0.3.1...v0.4.0) (2023-05-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* visual block mode support ([5765e3d](https://github.com/chenasraf/text-transform.nvim/commit/5765e3d72109c473b4f9ab8839d01f8c983d0dc2))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* word edge detection ([9cd27ab](https://github.com/chenasraf/text-transform.nvim/commit/9cd27aba2b74b072d57edadecdd63646d84a82cf))
|
||||
* words split ([43cc07c](https://github.com/chenasraf/text-transform.nvim/commit/43cc07cde43e8a4caf6a9c7471f6e3e69e67c242))
|
||||
|
||||
## [0.3.1](https://github.com/chenasraf/text-transform.nvim/compare/v0.3.0...v0.3.1) (2023-05-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* into_words dot split ([f79799c](https://github.com/chenasraf/text-transform.nvim/commit/f79799cd912436e48ee2bcde7a5d98042337f8ae))
|
||||
|
||||
## [0.3.0](https://github.com/chenasraf/text-transform.nvim/compare/v0.2.1...v0.3.0) (2023-05-16)
|
||||
|
||||
|
||||
|
||||
@@ -9,4 +9,7 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: ["https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=TSH3C3ABGQM22¤cy_code=ILS&source=url"]
|
||||
custom:
|
||||
[
|
||||
'https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=TSH3C3ABGQM22¤cy_code=ILS&source=url',
|
||||
]
|
||||
|
||||
13
Makefile
13
Makefile
@@ -14,6 +14,10 @@ test:
|
||||
deps:
|
||||
@mkdir -p deps
|
||||
git clone --depth 1 https://github.com/echasnovski/mini.nvim deps/mini.nvim
|
||||
git clone --depth 1 https://github.com/nvim-lua/plenary.nvim deps/plenary.nvim
|
||||
git clone --depth 1 https://github.com/nvim-telescope/telescope.nvim deps/telescope.nvim
|
||||
echo "#!/usr/bin/env bash\n\nmake precommit" > .git/hooks/pre-commit
|
||||
chmod +x .git/hooks/pre-commit
|
||||
|
||||
# installs deps before running tests, useful for the CI.
|
||||
test-ci: deps test
|
||||
@@ -29,6 +33,9 @@ documentation-ci: deps documentation
|
||||
lint:
|
||||
stylua .
|
||||
|
||||
# setup
|
||||
setup:
|
||||
./scripts/setup.sh
|
||||
# precommit
|
||||
precommit:
|
||||
./scripts/precommit.sh
|
||||
|
||||
clean:
|
||||
rm -rf deps
|
||||
|
||||
220
README.md
220
README.md
@@ -8,14 +8,23 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
## ⚡️ Features
|
||||
|
||||
Transform the current word or selection between multiple case types. Need to easily replace myVar
|
||||
with my_var or vice versa? This plugin is for you!
|
||||
Transform the current word or selection between multiple case types. Need to easily replace `myVar`
|
||||
with `my_var` or vice versa? This plugin is for you!
|
||||
|
||||
- Works on current word in **Normal Mode**
|
||||
- Will replace the current word selectable by <kbd>ciw</kbd>
|
||||
- Works on selection in **Visual Mode**
|
||||
- Will replace only inside the selection
|
||||
- Works on column selections in **Visual Block Mode**
|
||||
- Will detect if the block is a single column or multiple columns
|
||||
- If it's a single column, will replace the word under each cursor
|
||||
- If it's a selection with length, will replace only inside the selection ranges
|
||||
|
||||
| Transformation | Example Inputs | Output |
|
||||
| -------------- | --------------------------- | -------- |
|
||||
@@ -27,73 +36,55 @@ with my_var or vice versa? This plugin is for you!
|
||||
| `Title Case` | `my_var`, `my-var`, `MyVar` | `My Var` |
|
||||
| `CONST_CASE` | `my_var`, `my-var`, `MyVar` | `MY_VAR` |
|
||||
|
||||
## 📋 Installation
|
||||
## 🔽 Installation
|
||||
|
||||
<div align="center">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Package manager</th>
|
||||
<th>Snippet</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
[wbthomason/packer.nvim](https://github.com/wbthomason/packer.nvim)
|
||||
|
||||
</td>
|
||||
<td>
|
||||
### [Lazy](https://github.com/folke/lazy.nvim)
|
||||
|
||||
```lua
|
||||
-- stable version
|
||||
use { "chenasraf/text-transform.nvim", tag = "*" }
|
||||
-- dev version
|
||||
use { "chenasraf/text-transform.nvim" }
|
||||
require("lazy").setup({
|
||||
"chenasraf/text-transform.nvim",
|
||||
-- stable version
|
||||
version = "*", -- or: tag = "stable"
|
||||
-- dev version
|
||||
-- branch = "develop",
|
||||
-- Optional - for Telescope popup
|
||||
dependencies = { 'nvim-telescope/telescope.nvim', 'nvim-lua/plenary.nvim' }
|
||||
})
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
[junegunn/vim-plug](https://github.com/junegunn/vim-plug)
|
||||
|
||||
</td>
|
||||
<td>
|
||||
### [Packer](https://github.com/wbthomason/packer.nvim)
|
||||
|
||||
```lua
|
||||
-- stable version
|
||||
Plug "chenasraf/text-transform.nvim", { "tag": "*" }
|
||||
-- dev version
|
||||
Plug "chenasraf/text-transform.nvim"
|
||||
use { "chenasraf/text-transform.nvim",
|
||||
-- stable version
|
||||
tag = "stable",
|
||||
-- dev version
|
||||
-- branch = "develop",
|
||||
-- Optional - for Telescope popup
|
||||
requires = { 'nvim-telescope/telescope.nvim', 'nvim-lua/plenary.nvim' }
|
||||
}
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
### [Plug](https://github.com/junegunn/vim-plug)
|
||||
|
||||
[folke/lazy.nvim](https://github.com/folke/lazy.nvim)
|
||||
```vim
|
||||
" Dependencies - optional for Telescope popup
|
||||
Plug 'nvim-telescope/telescope.nvim'
|
||||
Plug 'nvim-lua/plenary.nvim'
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
```lua
|
||||
-- stable version
|
||||
require("lazy").setup({{ "chenasraf/text-transform.nvim", version = "*" }})
|
||||
-- dev version
|
||||
require("lazy").setup({ "chenasraf/text-transform.nvim" })
|
||||
" stable version
|
||||
Plug 'chenasraf/text-transform.nvim', { 'tag': 'stable' }
|
||||
" dev version
|
||||
Plug 'chenasraf/text-transform.nvim', { 'branch': 'develop' }
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
If you decide not to use Telescope, you can ignore the dependencies. In that case, be sure to change
|
||||
your config with `popup_type = 'select'` so that TextTransform never tries to load Telescope.
|
||||
|
||||
## ☄ Getting started
|
||||
It falls back to `vim.ui.select()` instead, which may or may not still be Telescope behind the
|
||||
scenes, or something else; depending on your setup.
|
||||
|
||||
## 🚀 Getting started
|
||||
|
||||
To get started, [install](#-installation) the plugin via your favorite package manager.
|
||||
|
||||
@@ -112,42 +103,113 @@ To get started, [install](#-installation) the plugin via your favorite package m
|
||||
|
||||
1. Select the desired transform and you're done!
|
||||
|
||||
## ⚙ Configuration
|
||||
## ⚙️ Configuration
|
||||
|
||||
<details>
|
||||
<summary>Click to unfold the full list of options with their default values</summary>
|
||||
> **Note**: The options are also available in Neovim by calling `:h TextTransform.options`
|
||||
|
||||
> **Note**: The options are also available in Neovim by calling `:h text-transform.options`
|
||||
The following are the default options when none are configured by the user.
|
||||
|
||||
To merge any new config into the default, you can override only the keys you need, and leave the
|
||||
rest to use the defaults.
|
||||
|
||||
```lua
|
||||
require("text-transform").setup({
|
||||
-- Prints useful logs about what event are triggered, and reasons actions are executed.
|
||||
--- Prints information about internals of the plugin. Very verbose, only useful for debugging.
|
||||
debug = false,
|
||||
-- Keymap to trigger the transform.
|
||||
--- Keymap configurations
|
||||
keymap = {
|
||||
-- Normal mode keymap.
|
||||
["n"] = "<Leader>~",
|
||||
-- Visual mode keymap.
|
||||
["v"] = "<Leader>~",
|
||||
--- Keymap to open the telescope popup. Set to `false` or `nil` to disable keymapping
|
||||
--- You can always customize your own keymapping manually.
|
||||
telescope_popup = {
|
||||
--- Opens the popup in normal mode
|
||||
["n"] = "<Leader>~",
|
||||
--- Opens the popup in visual/visual block modes
|
||||
["v"] = "<Leader>~",
|
||||
},
|
||||
},
|
||||
---
|
||||
--- Configurations for the text-transform replacers
|
||||
--- Keys indicate the replacer name, and the value is a table with the following options:
|
||||
---
|
||||
--- - `enabled` (boolean): Enable or disable the replacer - disabled replacers do not show up in the popup.
|
||||
replacers = {
|
||||
camel_case = { enabled = true },
|
||||
const_case = { enabled = true },
|
||||
dot_case = { enabled = true },
|
||||
kebab_case = { enabled = true },
|
||||
pascal_case = { enabled = true },
|
||||
snake_case = { enabled = true },
|
||||
title_case = { enabled = true },
|
||||
},
|
||||
|
||||
--- Sort the replacers in the popup.
|
||||
--- Possible values: 'frequency', 'name'
|
||||
sort_by = "frequency",
|
||||
|
||||
--- The popup type to show.
|
||||
--- Possible values: 'telescope', 'select'
|
||||
popup_type = 'telescope'
|
||||
})
|
||||
```
|
||||
|
||||
## 📝 Commands
|
||||
|
||||
The following commands are available for your use in your own mappings or for reference.
|
||||
|
||||
| Command | Description |
|
||||
| ---------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| `:TextTransform` | Pop up a either a Telescope window or a selection popup, depending on the `popup_type` config. |
|
||||
| `:TtTelescope` | Pop up a Telescope window with all the transformers, which will directly act on the selected text or highlighted word. |
|
||||
| `:TtSelect` | Pop up a selection popup with all the transformers, which will directly act on the selected text or highlighted word. |
|
||||
| `:TtCamel` | Replace selection/word with `camelCase`. |
|
||||
| `:TtSnake` | Replace selection/word with `snake_case`. |
|
||||
| `:TtPascal` | Replace selection/word with `PascalCase`. |
|
||||
| `:TtConst` | Replace selection/word with `CONST_CASE`. |
|
||||
| `:TtDot` | Replace selection/word with `dot.case`. |
|
||||
| `:TtKebab` | Replace selection/word with `kebab-case`. |
|
||||
| `:TtTitle` | Replace selection/word with `Title Case`. |
|
||||
|
||||
## ⌨️⌨️ Keymaps
|
||||
|
||||
You can use the setup options to customize the default keymaps used to trigger the Telescope Popup.
|
||||
|
||||
To disable these automated mappings, pass `nil` or `false` to the containing table (e.g.
|
||||
`telescope_popup`) or to the keys themselves.
|
||||
|
||||
```lua
|
||||
-- Disable entirely
|
||||
require("text-transform").setup({
|
||||
keymap = {
|
||||
telescope_popup = nil,
|
||||
},
|
||||
})
|
||||
-- Disable just one keymap
|
||||
require("text-transform").setup({
|
||||
keymap = {
|
||||
telescope_popup = {
|
||||
["v"] = nil,
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
</details>
|
||||
You can also create custom mappings to specific case conversions or to the Telescope popup yourself.
|
||||
|
||||
## 🧰 Commands
|
||||
```lua
|
||||
-- Trigger telescope popup
|
||||
vim.keymap.set("n", "<leader>~~", ":TtTelescope", { silent = true, desc = "Transform Text" })
|
||||
|
||||
Use the following as example, you can mix & match the different replacement functions with the
|
||||
desired transform function.
|
||||
-- Trigger case converters directly
|
||||
vim.keymap.set({ "n", "v" }, "<leader>Ccc", ":TtCamel", { silent = true, desc = "To camelCase" })
|
||||
vim.keymap.set({ "n", "v" }, "<leader>Csn", ":TtSnake", { silent = true, desc = "To snake_case" })
|
||||
vim.keymap.set({ "n", "v" }, "<leader>Cpa", ":TtPascal", { silent = true, desc = "To PascalCase" })
|
||||
vim.keymap.set({ "n", "v" }, "<leader>Cco", ":TtConst", { silent = true, desc = "To CONST_CASE" })
|
||||
vim.keymap.set({ "n", "v" }, "<leader>Cdo", ":TtDot", { silent = true, desc = "To dot.case" })
|
||||
vim.keymap.set({ "n", "v" }, "<leader>Cke", ":TtKebab", { silent = true, desc = "To kebab-case" })
|
||||
vim.keymap.set({ "n", "v" }, "<leader>Ctt", ":TtTitle", { silent = true, desc = "To Title Case" })
|
||||
```
|
||||
|
||||
Normally you wouldn't need to call this, as you would just use the keymap you used in `setup()`.
|
||||
|
||||
| Command | Description |
|
||||
| ---------------------------------------------------------------- | -------------------------------------------------- |
|
||||
| `:lua TextTransform.replace_word(TextTransform.camel_case)` | Replaces selected word with camelCase version. |
|
||||
| `:lua TextTransform.replace_selection(TextTransform.snake_case)` | Replaces visual selection with snake_case version. |
|
||||
|
||||
## ⌨ Contributing
|
||||
## 💁🏻 Contributing
|
||||
|
||||
I am developing this package on my free time, so any support, whether code, issues, or just stars is
|
||||
very helpful to sustaining its life. If you are feeling incredibly generous and would like to donate
|
||||
|
||||
23
doc/tags
23
doc/tags
@@ -1,2 +1,23 @@
|
||||
TextTransform.options text-transform.txt /*TextTransform.options*
|
||||
TextTransform.config text-transform.txt /*TextTransform.config*
|
||||
TextTransform.get_visual_selection_details() text-transform.txt /*TextTransform.get_visual_selection_details()*
|
||||
TextTransform.merge() text-transform.txt /*TextTransform.merge()*
|
||||
TextTransform.replace_columns() text-transform.txt /*TextTransform.replace_columns()*
|
||||
TextTransform.replace_range() text-transform.txt /*TextTransform.replace_range()*
|
||||
TextTransform.replace_selection() text-transform.txt /*TextTransform.replace_selection()*
|
||||
TextTransform.replace_word() text-transform.txt /*TextTransform.replace_word()*
|
||||
TextTransform.restore_positions() text-transform.txt /*TextTransform.restore_positions()*
|
||||
TextTransform.save_positions() text-transform.txt /*TextTransform.save_positions()*
|
||||
TextTransform.select_popup() text-transform.txt /*TextTransform.select_popup()*
|
||||
TextTransform.setup() text-transform.txt /*TextTransform.setup()*
|
||||
TextTransform.show_popup() text-transform.txt /*TextTransform.show_popup()*
|
||||
TextTransform.telescope_popup() text-transform.txt /*TextTransform.telescope_popup()*
|
||||
TextTransform.to_camel_case() text-transform.txt /*TextTransform.to_camel_case()*
|
||||
TextTransform.to_const_case() text-transform.txt /*TextTransform.to_const_case()*
|
||||
TextTransform.to_dot_case() text-transform.txt /*TextTransform.to_dot_case()*
|
||||
TextTransform.to_kebab_case() text-transform.txt /*TextTransform.to_kebab_case()*
|
||||
TextTransform.to_pascal_case() text-transform.txt /*TextTransform.to_pascal_case()*
|
||||
TextTransform.to_snake_case() text-transform.txt /*TextTransform.to_snake_case()*
|
||||
TextTransform.to_title_case() text-transform.txt /*TextTransform.to_title_case()*
|
||||
TextTransform.to_words() text-transform.txt /*TextTransform.to_words()*
|
||||
TextTransform.transform_words() text-transform.txt /*TextTransform.transform_words()*
|
||||
find_word_boundaries() text-transform.txt /*find_word_boundaries()*
|
||||
|
||||
@@ -1,35 +1,277 @@
|
||||
==============================================================================
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.options*
|
||||
`TextTransform.options`
|
||||
*TextTransform.config*
|
||||
`TextTransform.config`
|
||||
Your plugin configuration with its default values.
|
||||
|
||||
Default values:
|
||||
>
|
||||
TextTransform.options = {
|
||||
-- Prints useful logs about what event are triggered, and reasons actions are executed.
|
||||
>lua
|
||||
TextTransform.config = {
|
||||
--- Prints information about internals of the plugin. Very verbose, only useful for debugging.
|
||||
debug = false,
|
||||
-- Keymap to trigger the transform.
|
||||
--- Keymap configurations
|
||||
keymap = {
|
||||
-- Normal mode keymap.
|
||||
["n"] = "<Leader>~",
|
||||
-- Visual mode keymap.
|
||||
["v"] = "<Leader>~",
|
||||
--- Keymap to open the telescope popup. Set to `false` or `nil` to disable keymapping
|
||||
--- You can always customize your own keymapping manually.
|
||||
telescope_popup = {
|
||||
--- Opens the popup in normal mode
|
||||
["n"] = "<Leader>~",
|
||||
--- Opens the popup in visual/visual block modes
|
||||
["v"] = "<Leader>~",
|
||||
},
|
||||
},
|
||||
---
|
||||
--- Configurations for the text-transform replacers
|
||||
--- Keys indicate the replacer name, and the value is a table with the following options:
|
||||
---
|
||||
--- - `enabled` (boolean): Enable or disable the replacer - disabled replacers do not show up in the popup.
|
||||
replacers = {
|
||||
camel_case = { enabled = true },
|
||||
const_case = { enabled = true },
|
||||
dot_case = { enabled = true },
|
||||
kebab_case = { enabled = true },
|
||||
pascal_case = { enabled = true },
|
||||
snake_case = { enabled = true },
|
||||
title_case = { enabled = true },
|
||||
},
|
||||
|
||||
--- Sort the replacers in the popup.
|
||||
--- Possible values: 'frequency', 'name'
|
||||
sort_by = "frequency",
|
||||
|
||||
--- The popup type to show.
|
||||
--- Possible values: 'telescope', 'select'
|
||||
popup_type = "telescope",
|
||||
}
|
||||
|
||||
<
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.setup()*
|
||||
`TextTransform.setup`({options})
|
||||
Define your text-transform setup.
|
||||
|
||||
Parameters~
|
||||
Parameters ~
|
||||
{options} `(table)` Module config table. See |TextTransform.options|.
|
||||
|
||||
Usage~
|
||||
Usage ~
|
||||
`require("text-transform").setup()` (add `{}` with your |TextTransform.options| table)
|
||||
|
||||
|
||||
==============================================================================
|
||||
------------------------------------------------------------------------------
|
||||
*find_word_boundaries()*
|
||||
`find_word_boundaries`({line}, {start_col})
|
||||
Finds the boundaries of the surrounding word around `start_col` within `line`.
|
||||
Parameters ~
|
||||
{line} `(number)`
|
||||
{start_col} `(number)`
|
||||
Return ~
|
||||
`(number)` start_col, number end_col
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.replace_range()*
|
||||
`TextTransform.replace_range`({start_line}, {start_col}, {end_line}, {end_col}, {transform_name})
|
||||
Replace the range between the given positions with the given transform.
|
||||
Acts on the lines between the given positions, replacing the text between the given columns.
|
||||
|
||||
Parameters ~
|
||||
{start_line} `(number)` The starting line
|
||||
{start_col} `(number)` The starting column
|
||||
{end_line} `(number)` The ending line
|
||||
{end_col} `(number)` The ending column
|
||||
{transform_name} `(string)` The transformer name
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.replace_word()*
|
||||
`TextTransform.replace_word`({transform_name}, {position})
|
||||
Replace the word under the cursor with the given transform.
|
||||
If `position` is provided, replace the word under the given position.
|
||||
Otherwise, attempts to find the word under the cursor.
|
||||
|
||||
Parameters ~
|
||||
{transform_name} `(string)` The transformer name
|
||||
{position} `(table|nil)` A table containing the position of the word to replace
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.replace_columns()*
|
||||
`TextTransform.replace_columns`({transform_name})
|
||||
Replaces each column in visual block mode selection with the given transform.
|
||||
Assumes that the each selection is 1 character and operates on the whole word under each cursor.
|
||||
|
||||
Parameters ~
|
||||
{transform_name} `(string)` The transformer name
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.replace_selection()*
|
||||
`TextTransform.replace_selection`({transform_name})
|
||||
Replaces a selection with the given transform. This function attempts to infer the replacement
|
||||
type based on the cursor positiono and visual selections, and passes information to relevant
|
||||
range replacement functions.
|
||||
|
||||
Parameters ~
|
||||
{transform_name} `(string)` The transformer name
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.get_visual_selection_details()*
|
||||
`TextTransform.get_visual_selection_details`()
|
||||
Takes the saved positions and translates them into individual visual ranges, regardless of how
|
||||
the original selection was performed.
|
||||
|
||||
This allows to treat all ranges equally and allows to work on each selection without knowing
|
||||
the full information around the selection logic.
|
||||
|
||||
|
||||
==============================================================================
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.save_positions()*
|
||||
`TextTransform.save_positions`()
|
||||
Save the current cursor position, mode, and visual selection ranges
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.restore_positions()*
|
||||
`TextTransform.restore_positions`({positions})
|
||||
Restore the cursor position, mode, and visual selection ranges saved using `save_position()`,
|
||||
or a given modified state, if passed as the first argument
|
||||
|
||||
|
||||
==============================================================================
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.to_words()*
|
||||
`TextTransform.to_words`({string})
|
||||
Splits a string into words.
|
||||
Parameters ~
|
||||
{string} `(string)`
|
||||
Return ~
|
||||
`(table)`
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.transform_words()*
|
||||
`TextTransform.transform_words`({words}, {with_word_cb}, {separator})
|
||||
Transforms a table of strings into a string using a callback and separator.
|
||||
The callback is called with the word, the index, and the table of words.
|
||||
The separator is added between each word.
|
||||
|
||||
Parameters ~
|
||||
{words} `(string|table)` string or table of strings
|
||||
{with_word_cb} `(function)` (word: string, index: number, words: table) -> string
|
||||
{separator} `(string|nil)` (optional)
|
||||
Return ~
|
||||
`(string)`
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.to_camel_case()*
|
||||
`TextTransform.to_camel_case`({string})
|
||||
Transforms a string into camelCase.
|
||||
Parameters ~
|
||||
{string} `(string)`
|
||||
Return ~
|
||||
`(string)`
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.to_snake_case()*
|
||||
`TextTransform.to_snake_case`({string})
|
||||
Transfroms a string into snake_case.
|
||||
Parameters ~
|
||||
{string} `(any)`
|
||||
Return ~
|
||||
`(string)`
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.to_pascal_case()*
|
||||
`TextTransform.to_pascal_case`({string})
|
||||
Transforms a string into PascalCase.
|
||||
Parameters ~
|
||||
{string} `(string)`
|
||||
Return ~
|
||||
`(string)`
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.to_title_case()*
|
||||
`TextTransform.to_title_case`({string})
|
||||
Transforms a string into Title Case.
|
||||
Parameters ~
|
||||
{string} `(string)`
|
||||
Return ~
|
||||
`(string)`
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.to_kebab_case()*
|
||||
`TextTransform.to_kebab_case`({string})
|
||||
Transforms a string into kebab-case.
|
||||
Parameters ~
|
||||
{string} `(string)`
|
||||
Return ~
|
||||
`(string)`
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.to_dot_case()*
|
||||
`TextTransform.to_dot_case`({string})
|
||||
Transforms a string into dot.case.
|
||||
Parameters ~
|
||||
{string} `(string)`
|
||||
Return ~
|
||||
`(string)`
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.to_const_case()*
|
||||
`TextTransform.to_const_case`({string})
|
||||
Transforms a string into CONSTANT_CASE.
|
||||
Parameters ~
|
||||
{string} `(string)`
|
||||
Return ~
|
||||
`(string)`
|
||||
|
||||
|
||||
==============================================================================
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.show_popup()*
|
||||
`TextTransform.show_popup`()
|
||||
Pops up a selection menu, containing the available case transformers.
|
||||
When a transformer is selected, the cursor position/range/columns will be used to replace the
|
||||
words around the cursor or inside the selection.
|
||||
|
||||
The cursor positions/ranges are saved before opening the menu and restored once a selection is
|
||||
made.
|
||||
|
||||
|
||||
==============================================================================
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.select_popup()*
|
||||
`TextTransform.select_popup`()
|
||||
Pops up a selection menu, containing the available case transformers.
|
||||
When a transformer is selected, the cursor position/range/columns will be used to replace the
|
||||
words around the cursor or inside the selection.
|
||||
|
||||
The cursor positions/ranges are saved before opening the menu and restored once a selection is
|
||||
made.
|
||||
|
||||
|
||||
==============================================================================
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.telescope_popup()*
|
||||
`TextTransform.telescope_popup`()
|
||||
Pops up a telescope menu, containing the available case transformers.
|
||||
When a transformer is selected, the cursor position/range/columns will be used to replace the
|
||||
words around the cursor or inside the selection.
|
||||
|
||||
The cursor positions/ranges are saved before opening the menu and restored once a selection is
|
||||
made.
|
||||
|
||||
|
||||
==============================================================================
|
||||
------------------------------------------------------------------------------
|
||||
*TextTransform.merge()*
|
||||
`TextTransform.merge`({t1}, {t2})
|
||||
Merges two tables into one. Same as `vim.tbl_extend("keep", t1, t2)`.
|
||||
Mutates the first table.
|
||||
|
||||
TODO accept multiple tables to merge
|
||||
|
||||
Parameters ~
|
||||
{t1} `(table)`
|
||||
{t2} `(table)`
|
||||
Return ~
|
||||
`(table)`
|
||||
|
||||
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
71
lua/text-transform/commands.lua
Normal file
71
lua/text-transform/commands.lua
Normal file
@@ -0,0 +1,71 @@
|
||||
local D = require("text-transform.utils.debug")
|
||||
local util = require("text-transform.utils")
|
||||
local state = require("text-transform.state")
|
||||
local replacers = require("text-transform.replacers")
|
||||
local popup = require("text-transform.popup")
|
||||
local common = require("text-transform.popup.common")
|
||||
|
||||
local TextTransform = {}
|
||||
|
||||
function TextTransform.init_commands()
|
||||
local map = {
|
||||
TtCamel = "camel_case",
|
||||
TtConst = "const_case",
|
||||
TtDot = "dot_case",
|
||||
TtKebab = "kebab_case",
|
||||
TtPascal = "pascal_case",
|
||||
TtSnake = "snake_case",
|
||||
TtTitle = "title_case",
|
||||
}
|
||||
|
||||
local cmdopts = { range = true, force = true }
|
||||
local opts = function(desc)
|
||||
return util.merge(cmdopts, { desc = desc })
|
||||
end
|
||||
|
||||
for cmd, transformer_name in pairs(map) do
|
||||
local item
|
||||
for _, t in ipairs(common.items) do
|
||||
if t.value == transformer_name then
|
||||
item = t.label
|
||||
break
|
||||
end
|
||||
end
|
||||
vim.api.nvim_create_user_command(cmd, function()
|
||||
state.save_positions()
|
||||
replacers.replace_selection(transformer_name)
|
||||
vim.schedule(function()
|
||||
state.restore_positions()
|
||||
end)
|
||||
end, opts("Change to " .. item))
|
||||
end
|
||||
|
||||
-- specific popups
|
||||
vim.api.nvim_create_user_command("TtTelescope", function()
|
||||
local telescope = require("text-transform.popup.telescope")
|
||||
telescope.telescope_popup()
|
||||
end, opts("Change Case with Telescope"))
|
||||
vim.api.nvim_create_user_command("TtSelect", function()
|
||||
local select = require("text-transform.popup.select")
|
||||
select.select_popup()
|
||||
end, opts("Change Case with Select"))
|
||||
|
||||
-- auto popup by config
|
||||
vim.api.nvim_create_user_command("TextTransform", popup.show_popup, opts("Change Case"))
|
||||
end
|
||||
|
||||
function TextTransform.init_keymaps()
|
||||
local keymaps = _G.TextTransform.config.keymap
|
||||
D.log("init_keymaps", "Initializing keymaps, config %s", vim.inspect(_G.TextTransform))
|
||||
if keymaps.telescope_popup then
|
||||
local keys = keymaps.telescope_popup
|
||||
if keys.n then
|
||||
vim.keymap.set("n", keys.n, popup.show_popup, { silent = true, desc = "Change Case" })
|
||||
end
|
||||
if keys.v then
|
||||
vim.keymap.set("v", keys.v, popup.show_popup, { silent = true, desc = "Change Case" })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return TextTransform
|
||||
@@ -1,19 +1,63 @@
|
||||
local commands = require("text-transform.commands")
|
||||
local D = require("text-transform.utils.debug")
|
||||
local utils = require("text-transform.utils")
|
||||
local TextTransform = {}
|
||||
|
||||
local function ensure_config()
|
||||
-- when the config is not set to the global object, we set it
|
||||
if _G.TextTransform.config == nil then
|
||||
_G.TextTransform.config = TextTransform.config
|
||||
end
|
||||
end
|
||||
|
||||
local function init()
|
||||
ensure_config()
|
||||
local o = TextTransform.config
|
||||
D.log("config", "Initializing TextTransform with %s", vim.inspect(o))
|
||||
commands.init_commands()
|
||||
commands.init_keymaps()
|
||||
end
|
||||
|
||||
--- Your plugin configuration with its default values.
|
||||
---
|
||||
--- Default values:
|
||||
---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)
|
||||
TextTransform.options = {
|
||||
-- Prints useful logs about what event are triggered, and reasons actions are executed.
|
||||
TextTransform.config = {
|
||||
--- Prints information about internals of the plugin. Very verbose, only useful for debugging.
|
||||
debug = false,
|
||||
-- Keymap to trigger the transform.
|
||||
--- Keymap configurations
|
||||
keymap = {
|
||||
-- Normal mode keymap.
|
||||
["n"] = "<Leader>~",
|
||||
-- Visual mode keymap.
|
||||
["v"] = "<Leader>~",
|
||||
--- Keymap to open the telescope popup. Set to `false` or `nil` to disable keymapping
|
||||
--- You can always customize your own keymapping manually.
|
||||
telescope_popup = {
|
||||
--- Opens the popup in normal mode
|
||||
["n"] = "<Leader>~",
|
||||
--- Opens the popup in visual/visual block modes
|
||||
["v"] = "<Leader>~",
|
||||
},
|
||||
},
|
||||
---
|
||||
--- Configurations for the text-transform replacers
|
||||
--- Keys indicate the replacer name, and the value is a table with the following options:
|
||||
---
|
||||
--- - `enabled` (boolean): Enable or disable the replacer - disabled replacers do not show up in the popup.
|
||||
replacers = {
|
||||
camel_case = { enabled = true },
|
||||
const_case = { enabled = true },
|
||||
dot_case = { enabled = true },
|
||||
kebab_case = { enabled = true },
|
||||
pascal_case = { enabled = true },
|
||||
snake_case = { enabled = true },
|
||||
title_case = { enabled = true },
|
||||
},
|
||||
|
||||
--- Sort the replacers in the popup.
|
||||
--- Possible values: 'frequency', 'name'
|
||||
sort_by = "frequency",
|
||||
|
||||
--- The popup type to show.
|
||||
--- Possible values: 'telescope', 'select'
|
||||
popup_type = "telescope",
|
||||
}
|
||||
|
||||
--- Define your text-transform setup.
|
||||
@@ -24,39 +68,17 @@ TextTransform.options = {
|
||||
function TextTransform.setup(options)
|
||||
options = options or {}
|
||||
|
||||
TextTransform.options = vim.tbl_deep_extend("keep", options, TextTransform.options)
|
||||
TextTransform.config = utils.merge(TextTransform.config, options)
|
||||
|
||||
local map = {
|
||||
["&camelCase"] = "TextTransform.camel_case",
|
||||
["&snake_case"] = "TextTransform.snake_case",
|
||||
["&PascalCase"] = "TextTransform.pascal_case",
|
||||
["&kebab-case"] = "TextTransform.kebab_case",
|
||||
["&dot\\.case"] = "TextTransform.dot_case",
|
||||
["&Title\\ Case"] = "TextTransform.title_case",
|
||||
["C&ONST_CASE"] = "TextTransform.const_case",
|
||||
}
|
||||
|
||||
for k, v in pairs(map) do
|
||||
vim.cmd("amenu TransformsWord." .. k .. " :lua TextTransform.replace_word(" .. v .. ")<CR>")
|
||||
vim.cmd(
|
||||
"amenu TransformsSelection." .. k .. " :lua TextTransform.replace_selection(" .. v .. ")<CR>"
|
||||
)
|
||||
if vim.api.nvim_get_vvar("vim_did_enter") == 0 then
|
||||
vim.defer_fn(function()
|
||||
init()
|
||||
end, 0)
|
||||
else
|
||||
init()
|
||||
end
|
||||
|
||||
vim.keymap.set(
|
||||
"n",
|
||||
TextTransform.options.keymap.n,
|
||||
"<cmd>popup TransformsWord<CR>",
|
||||
{ silent = true }
|
||||
)
|
||||
vim.keymap.set(
|
||||
"v",
|
||||
TextTransform.options.keymap.v,
|
||||
"<cmd>popup TransformsSelection<CR>",
|
||||
{ silent = true }
|
||||
)
|
||||
|
||||
return TextTransform.options
|
||||
return TextTransform.config
|
||||
end
|
||||
|
||||
return TextTransform
|
||||
|
||||
@@ -1,41 +1,23 @@
|
||||
local M = require("text-transform.main")
|
||||
local utils = require("text-transform.utils")
|
||||
local tt = require("text-transform.transformers")
|
||||
local replacers = require("text-transform.replacers")
|
||||
local state = require("text-transform.state")
|
||||
local popup = require("text-transform.popup")
|
||||
|
||||
local TextTransform = {}
|
||||
|
||||
-- Toggle the plugin by calling the `enable`/`disable` methods respectively.
|
||||
function TextTransform.toggle()
|
||||
-- when the config is not set to the global object, we set it
|
||||
if _G.TextTransform.config == nil then
|
||||
_G.TextTransform.config = require("text-transform.config").options
|
||||
end
|
||||
|
||||
_G.TextTransform.state = M.toggle()
|
||||
end
|
||||
|
||||
-- starts TextTransform and set internal functions and state.
|
||||
function TextTransform.enable()
|
||||
if _G.TextTransform.config == nil then
|
||||
_G.TextTransform.config = require("text-transform.config").options
|
||||
end
|
||||
|
||||
local state = M.enable()
|
||||
|
||||
if state ~= nil then
|
||||
_G.TextTransform.state = state
|
||||
end
|
||||
|
||||
return state
|
||||
end
|
||||
|
||||
-- disables TextTransform and reset internal functions and state.
|
||||
function TextTransform.disable()
|
||||
_G.TextTransform.state = M.disable()
|
||||
end
|
||||
|
||||
-- setup TextTransform options and merge them with user provided ones.
|
||||
function TextTransform.setup(opts)
|
||||
_G.TextTransform.config = require("text-transform.config").setup(opts)
|
||||
end
|
||||
|
||||
_G.TextTransform = TextTransform
|
||||
local function merge(table)
|
||||
TextTransform = utils.merge(TextTransform, table)
|
||||
end
|
||||
|
||||
merge(tt)
|
||||
merge(replacers)
|
||||
merge(state)
|
||||
merge(popup)
|
||||
|
||||
_G.TextTransform = TextTransform
|
||||
return _G.TextTransform
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
local D = require("text-transform.util.debug")
|
||||
|
||||
-- internal methods
|
||||
local TextTransform = {}
|
||||
|
||||
-- state
|
||||
local S = {
|
||||
-- Boolean determining if the plugin is enabled or not.
|
||||
enabled = false,
|
||||
}
|
||||
|
||||
---Toggle the plugin by calling the `enable`/`disable` methods respectively.
|
||||
---@private
|
||||
function TextTransform.toggle()
|
||||
if S.enabled then
|
||||
return TextTransform.disable()
|
||||
end
|
||||
|
||||
return TextTransform.enable()
|
||||
end
|
||||
|
||||
---Initializes the plugin.
|
||||
---@private
|
||||
function TextTransform.enable()
|
||||
if S.enabled then
|
||||
return S
|
||||
end
|
||||
|
||||
S.enabled = true
|
||||
|
||||
return S
|
||||
end
|
||||
|
||||
---Disables the plugin and reset the internal state.
|
||||
---@private
|
||||
function TextTransform.disable()
|
||||
if not S.enabled then
|
||||
return S
|
||||
end
|
||||
|
||||
-- reset the state
|
||||
S = {
|
||||
enabled = false,
|
||||
}
|
||||
|
||||
return S
|
||||
end
|
||||
|
||||
return TextTransform
|
||||
67
lua/text-transform/popup/common.lua
Normal file
67
lua/text-transform/popup/common.lua
Normal file
@@ -0,0 +1,67 @@
|
||||
local D = require("text-transform.utils.debug")
|
||||
local state = require("text-transform.state")
|
||||
local replacers = require("text-transform.replacers")
|
||||
|
||||
local popup_common = {}
|
||||
|
||||
popup_common.items = {
|
||||
{ label = "camelCase", value = "camel_case" },
|
||||
{ label = "snake_case", value = "snake_case" },
|
||||
{ label = "PascalCase", value = "pascal_case" },
|
||||
{ label = "kebab-case", value = "kebab_case" },
|
||||
{ label = "dot.case", value = "dot_case" },
|
||||
{ label = "Title Case", value = "title_case" },
|
||||
{ label = "CONST_CASE", value = "const_case" },
|
||||
}
|
||||
|
||||
popup_common.default_frequency = {
|
||||
camel_case = 1,
|
||||
snake_case = 1,
|
||||
pascal_case = 1,
|
||||
kebab_case = 1,
|
||||
dot_case = 1,
|
||||
title_case = 1,
|
||||
const_case = 1,
|
||||
}
|
||||
|
||||
local cache_dir = vim.fn.stdpath("cache")
|
||||
local frequency_file = cache_dir .. "/text-transform-frequency.json"
|
||||
local frequency
|
||||
|
||||
function popup_common.load_frequency()
|
||||
if frequency then
|
||||
return frequency
|
||||
end
|
||||
if vim.fn.filereadable(frequency_file) == 0 then
|
||||
frequency = popup_common.default_frequency
|
||||
vim.fn.writefile({ vim.fn.json_encode(frequency) }, frequency_file)
|
||||
else
|
||||
frequency = vim.fn.json_decode(vim.fn.readfile(frequency_file))
|
||||
end
|
||||
D.log("telescope", "frequency loaded: %s", vim.inspect(frequency))
|
||||
return frequency
|
||||
end
|
||||
|
||||
function popup_common.inc_frequency(name)
|
||||
frequency[name] = (frequency[name] or 0) + 1
|
||||
D.log("telescope", "new frequency: %s %d", name, frequency[name])
|
||||
vim.fn.writefile({ vim.fn.json_encode(frequency) }, frequency_file)
|
||||
end
|
||||
|
||||
function popup_common.entry_maker(entry)
|
||||
return {
|
||||
value = entry.value,
|
||||
display = entry.label,
|
||||
ordinal = entry.label,
|
||||
frequency = frequency[entry.value] or 1,
|
||||
}
|
||||
end
|
||||
|
||||
function popup_common.select(selection)
|
||||
vim.schedule(function()
|
||||
replacers.replace_selection(selection.value)
|
||||
state.restore_positions()
|
||||
end)
|
||||
end
|
||||
|
||||
return popup_common
|
||||
20
lua/text-transform/popup/init.lua
Normal file
20
lua/text-transform/popup/init.lua
Normal file
@@ -0,0 +1,20 @@
|
||||
local TextTransform = {}
|
||||
|
||||
--- Pops up a selection menu, containing the available case transformers.
|
||||
--- When a transformer is selected, the cursor position/range/columns will be used to replace the
|
||||
--- words around the cursor or inside the selection.
|
||||
---
|
||||
--- The cursor positions/ranges are saved before opening the menu and restored once a selection is
|
||||
--- made.
|
||||
function TextTransform.show_popup()
|
||||
local config = _G.TextTransform.config
|
||||
if config.popup_type == "telescope" then
|
||||
local telescope = require("text-transform.popup.telescope")
|
||||
telescope.telescope_popup()
|
||||
else
|
||||
local select = require("text-transform.popup.select")
|
||||
select.select_popup()
|
||||
end
|
||||
end
|
||||
|
||||
return TextTransform
|
||||
30
lua/text-transform/popup/select.lua
Normal file
30
lua/text-transform/popup/select.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
local common = require("text-transform.popup.common")
|
||||
local state = require("text-transform.state")
|
||||
|
||||
local TextTransform = {}
|
||||
|
||||
--- Pops up a selection menu, containing the available case transformers.
|
||||
--- When a transformer is selected, the cursor position/range/columns will be used to replace the
|
||||
--- words around the cursor or inside the selection.
|
||||
---
|
||||
--- The cursor positions/ranges are saved before opening the menu and restored once a selection is
|
||||
--- made.
|
||||
function TextTransform.select_popup()
|
||||
common.load_frequency()
|
||||
state.save_positions()
|
||||
|
||||
vim.ui.select(common.items, {
|
||||
prompt = "Change Case",
|
||||
format_item = function(item)
|
||||
return item.label
|
||||
end,
|
||||
}, function(choice)
|
||||
if not choice then
|
||||
return
|
||||
end
|
||||
local item = common.entry_maker(choice)
|
||||
common.select(item)
|
||||
end)
|
||||
end
|
||||
|
||||
return TextTransform
|
||||
104
lua/text-transform/popup/telescope.lua
Normal file
104
lua/text-transform/popup/telescope.lua
Normal file
@@ -0,0 +1,104 @@
|
||||
local common = require("text-transform.popup.common")
|
||||
local D = require("text-transform.utils.debug")
|
||||
local state = require("text-transform.state")
|
||||
|
||||
local pickers = require("telescope.pickers")
|
||||
local finders = require("telescope.finders")
|
||||
local telescope_conf = require("telescope.config").values
|
||||
local actions = require("telescope.actions")
|
||||
local action_state = require("telescope.actions.state")
|
||||
local dropdown = require("telescope.themes").get_dropdown({})
|
||||
local Sorter = require("telescope.sorters").Sorter
|
||||
|
||||
local TextTransform = {}
|
||||
|
||||
local frequency_sorter = Sorter:new({
|
||||
---@diagnostic disable-next-line: unused-local
|
||||
scoring_function = function(self, prompt, line)
|
||||
local generic_sorter = telescope_conf.generic_sorter()
|
||||
generic_sorter:init()
|
||||
local entry
|
||||
for _, item in ipairs(common.items) do
|
||||
if item.label == line then
|
||||
entry = common.entry_maker(item)
|
||||
break
|
||||
end
|
||||
end
|
||||
D.log("frequency_sorter", "entry %s", vim.inspect(entry))
|
||||
D.log("frequency_sorter", "prompt %s line %s", prompt, line)
|
||||
-- Basic filtering based on prompt matching, non-matching items score below 0 to exclude them
|
||||
local basic_score = (generic_sorter:scoring_function(prompt, line) or 1)
|
||||
D.log("frequency_sorter", "%s basic_score: %s", entry.value, basic_score)
|
||||
if basic_score < 0 then
|
||||
return basic_score
|
||||
end
|
||||
|
||||
-- D.log("frequency_sorter", "entry: %s", vim.inspect(entry))
|
||||
-- D.log("frequency_sorter", "prompt: %s", prompt)
|
||||
-- Calculate score based on frequency, higher frequency should have lower score
|
||||
local freq_score = (entry.frequency or 1) * 10
|
||||
|
||||
D.log("frequency_sorter", "freq_score: %s", freq_score)
|
||||
|
||||
local final_score = 999999999 - freq_score + basic_score
|
||||
D.log("frequency_sorter", "%s final_score: %s", line, final_score)
|
||||
|
||||
-- Combine scores, with frequency having the primary influence if present
|
||||
return final_score
|
||||
end,
|
||||
})
|
||||
|
||||
local generic_sorter = telescope_conf.generic_sorter()
|
||||
local sorter_map = {
|
||||
frequency = frequency_sorter,
|
||||
name = generic_sorter,
|
||||
}
|
||||
|
||||
--- Pops up a telescope menu, containing the available case transformers.
|
||||
--- When a transformer is selected, the cursor position/range/columns will be used to replace the
|
||||
--- words around the cursor or inside the selection.
|
||||
---
|
||||
--- The cursor positions/ranges are saved before opening the menu and restored once a selection is
|
||||
--- made.
|
||||
function TextTransform.telescope_popup()
|
||||
state.save_positions()
|
||||
|
||||
local filtered = {}
|
||||
local config = _G.TextTransform.config
|
||||
local sorter = sorter_map[config.sort_by] or generic_sorter
|
||||
|
||||
if config.sort_by == "frequency" then
|
||||
common.load_frequency()
|
||||
end
|
||||
|
||||
for _, item in ipairs(common.items) do
|
||||
if config.replacers[item.value] and not config.replacers[item.value].enabled then
|
||||
goto continue
|
||||
end
|
||||
table.insert(filtered, item)
|
||||
::continue::
|
||||
end
|
||||
|
||||
local picker = pickers.new(dropdown, {
|
||||
prompt_title = "Change Case",
|
||||
finder = finders.new_table({
|
||||
results = common.items,
|
||||
entry_maker = common.entry_maker,
|
||||
}),
|
||||
sorter = sorter,
|
||||
attach_mappings = function(prompt_bufnr)
|
||||
actions.select_default:replace(function()
|
||||
local selection = action_state.get_selected_entry()
|
||||
common.inc_frequency(selection.value)
|
||||
actions.close(prompt_bufnr)
|
||||
common.select(selection)
|
||||
end)
|
||||
return true
|
||||
end,
|
||||
})
|
||||
vim.schedule(function()
|
||||
picker:find()
|
||||
end)
|
||||
end
|
||||
|
||||
return TextTransform
|
||||
233
lua/text-transform/replacers.lua
Normal file
233
lua/text-transform/replacers.lua
Normal file
@@ -0,0 +1,233 @@
|
||||
local D = require("text-transform.utils.debug")
|
||||
local S = require("text-transform.state")
|
||||
local t = require("text-transform.transformers")
|
||||
|
||||
local TextTransform = {}
|
||||
|
||||
--- Finds the boundaries of the surrounding word around `start_col` within `line`.
|
||||
---@param line number
|
||||
---@param start_col number
|
||||
---@return number start_col, number end_col
|
||||
local function find_word_boundaries(line, start_col)
|
||||
local line_text = vim.fn.getline(line)
|
||||
-- dashes, underscores, and periods are considered part of a word
|
||||
local word_pat = "[A-Za-z0-9_.\\-]"
|
||||
local non_word_pat = "[^A-Za-z0-9_.\\-]"
|
||||
-- TODO handle searching backwards
|
||||
local word_start_col = vim.fn.match(line_text:sub(start_col), word_pat) + start_col
|
||||
local word_end_col = vim.fn.match(line_text:sub(word_start_col), non_word_pat)
|
||||
+ word_start_col
|
||||
- 1
|
||||
D.log(
|
||||
"find_word_boundaries",
|
||||
"Found word boundaries: %s",
|
||||
vim.inspect({ word_start_col, word_end_col })
|
||||
)
|
||||
D.log("find_word_boundaries", "Word text: %s", line_text:sub(word_start_col, word_end_col))
|
||||
D.log("find_word_boundaries", "Line text: %s", line_text)
|
||||
return word_start_col, word_end_col
|
||||
end
|
||||
|
||||
--- Replace the range between the given positions with the given transform.
|
||||
--- Acts on the lines between the given positions, replacing the text between the given columns.
|
||||
---
|
||||
---@param start_line number The starting line
|
||||
---@param start_col number The starting column
|
||||
---@param end_line number The ending line
|
||||
---@param end_col number The ending column
|
||||
---@param transform_name string The transformer name
|
||||
function TextTransform.replace_range(start_line, start_col, end_line, end_col, transform_name)
|
||||
D.log("replace_range", "Replacing range with %s", transform_name)
|
||||
local transform = t["to_" .. transform_name]
|
||||
local lines = vim.fn.getline(start_line, end_line) ---@type any
|
||||
local transformed = {}
|
||||
if #lines == 1 then
|
||||
local line = lines[1]
|
||||
local before = line:sub(0, start_col - 1)
|
||||
local fixed = transform(line:sub(start_col, end_col))
|
||||
local after = line:sub(end_col + 1)
|
||||
table.insert(transformed, before .. fixed .. after)
|
||||
else
|
||||
for i, line in ipairs(lines) do
|
||||
if i == 1 then
|
||||
table.insert(transformed, line:sub(1, start_col - 1) .. transform(line:sub(start_col)))
|
||||
elseif i == #lines then
|
||||
table.insert(transformed, transform(line:sub(1, end_col)) .. line:sub(end_col + 1))
|
||||
else
|
||||
table.insert(transformed, transform(line))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vim.fn.setline(start_line, transformed)
|
||||
end
|
||||
|
||||
--- Replace the word under the cursor with the given transform.
|
||||
--- If `position` is provided, replace the word under the given position.
|
||||
--- Otherwise, attempts to find the word under the cursor.
|
||||
---
|
||||
---@param transform_name string The transformer name
|
||||
---@param position table|nil A table containing the position of the word to replace
|
||||
function TextTransform.replace_word(transform_name, position)
|
||||
D.log("replace_word", "Replacing word with %s", transform_name)
|
||||
local word, line, col, start_col, end_col
|
||||
if not position then
|
||||
word = vim.fn.expand("<cword>")
|
||||
else
|
||||
_, line, col = unpack(position)
|
||||
start_col, end_col = find_word_boundaries(line, col)
|
||||
word = vim.fn.getline(line):sub(start_col, end_col)
|
||||
end
|
||||
D.log("replace_word", "Found word %s", word)
|
||||
D.log("replace_word", "Using transformer %s", transform_name)
|
||||
local transformer = t["to_" .. transform_name]
|
||||
local transformed = transformer(word)
|
||||
D.log("replace_word", "New value %s", transformed)
|
||||
if not position then
|
||||
vim.cmd("normal ciw" .. transformed)
|
||||
else
|
||||
TextTransform.replace_range(line, start_col, line, end_col, transform_name)
|
||||
end
|
||||
end
|
||||
|
||||
--- Replaces each column in visual block mode selection with the given transform.
|
||||
--- Assumes that the each selection is 1 character and operates on the whole word under each cursor.
|
||||
---
|
||||
---@param transform_name string The transformer name
|
||||
function TextTransform.replace_columns(transform_name)
|
||||
local selections = TextTransform.get_visual_selection_details()
|
||||
D.log("replace_columns", "Replacing columns with %s", transform_name)
|
||||
for _, sel in ipairs(selections) do
|
||||
TextTransform.replace_word(transform_name, { 0, sel.start_line, sel.start_col, 0 })
|
||||
end
|
||||
end
|
||||
|
||||
--- Replaces a selection with the given transform. This function attempts to infer the replacement
|
||||
--- type based on the cursor positiono and visual selections, and passes information to relevant
|
||||
--- range replacement functions.
|
||||
---
|
||||
---@param transform_name string The transformer name
|
||||
function TextTransform.replace_selection(transform_name)
|
||||
D.log("replace_selection", "Replacing selection with %s", transform_name)
|
||||
-- determine if cursor is a 1-width column across multiple lines or a normal selection
|
||||
-- local start_line, start_col, end_line, end_col = unpack(vim.fn.getpos("'<"))
|
||||
local selections = TextTransform.get_visual_selection_details()
|
||||
|
||||
D.log("replace_selection", "Selections: %s", vim.inspect(selections))
|
||||
local is_multiline = #selections > 1
|
||||
local is_column = is_multiline and selections[1].start_col == selections[#selections].end_col
|
||||
local is_single_cursor = not is_multiline
|
||||
and not is_column
|
||||
and selections
|
||||
and selections[1]
|
||||
and selections[1].start_col == selections[1].end_col
|
||||
|
||||
D.log(
|
||||
"replace_selection",
|
||||
"is_multiline: %s, is_column: %s, is_word: %s",
|
||||
is_multiline,
|
||||
is_column,
|
||||
is_single_cursor
|
||||
)
|
||||
|
||||
if is_single_cursor then
|
||||
TextTransform.replace_word(transform_name)
|
||||
elseif is_column then
|
||||
TextTransform.replace_columns(transform_name)
|
||||
else
|
||||
for _, sel in pairs(selections) do
|
||||
TextTransform.replace_range(
|
||||
sel.start_line,
|
||||
sel.start_col,
|
||||
sel.end_line,
|
||||
sel.end_col,
|
||||
transform_name
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Takes the saved positions and translates them into individual visual ranges, regardless of how
|
||||
--- the original selection was performed.
|
||||
---
|
||||
--- This allows to treat all ranges equally and allows to work on each selection without knowing
|
||||
--- the full information around the selection logic.
|
||||
function TextTransform.get_visual_selection_details()
|
||||
if not S.state.positions.pos then
|
||||
D.log("get_visual_selection_details", "No positions saved")
|
||||
return {}
|
||||
end
|
||||
D.log(
|
||||
"get_visual_selection_details",
|
||||
"Getting visual selection details - mode: %s, is_visual: %s, is_block: %s",
|
||||
S.state.mode,
|
||||
S.is_visual_mode(),
|
||||
S.is_block_visual_mode()
|
||||
)
|
||||
|
||||
-- Get the start and end positions of the selection
|
||||
local start_pos = S.state.positions.visual_start
|
||||
local end_pos = S.state.positions.visual_end
|
||||
local start_line, start_col = start_pos[2], start_pos[3]
|
||||
local end_line, end_col = end_pos[2], end_pos[3]
|
||||
|
||||
-- Check if currently in visual mode; if not, return the cursor position
|
||||
if
|
||||
not S.is_visual_mode()
|
||||
and not S.is_block_visual_mode()
|
||||
and not S.has_range(start_pos, end_pos)
|
||||
then
|
||||
D.log("get_visual_selection_details", "Returning single cursor position: " .. vim.inspect(S))
|
||||
local pos = S.state.positions.pos
|
||||
return {
|
||||
{
|
||||
start_line = pos[2],
|
||||
end_line = pos[2],
|
||||
start_col = pos[3],
|
||||
end_col = pos[3],
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
-- Swap if selection is made upwards or backwards
|
||||
if start_line > end_line or (start_line == end_line and start_col > end_col) then
|
||||
start_line, end_line = end_line, start_line
|
||||
start_col, end_col = end_col, start_col
|
||||
end
|
||||
|
||||
-- If it's block visual mode, return table for each row
|
||||
if S.is_block_visual_mode() or S.has_range(start_pos, end_pos) then
|
||||
local block_selection = {}
|
||||
for line = start_line, end_line do
|
||||
if start_col == end_col then
|
||||
-- find the word surrounding the position
|
||||
start_col, _ = find_word_boundaries(line, start_col)
|
||||
end
|
||||
table.insert(block_selection, {
|
||||
start_line = line,
|
||||
end_line = line,
|
||||
start_col = start_col,
|
||||
end_col = start_col,
|
||||
})
|
||||
end
|
||||
D.log(
|
||||
"get_visual_selection_details",
|
||||
"Returning block selection: %s",
|
||||
vim.inspect(block_selection)
|
||||
)
|
||||
return block_selection
|
||||
else
|
||||
-- Normal visual mode, return single table entry
|
||||
D.log("get_visual_selection_details", "Returning normal selection")
|
||||
return {
|
||||
{
|
||||
start_line = start_line,
|
||||
end_line = end_line,
|
||||
start_col = start_col,
|
||||
end_col = end_col,
|
||||
},
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return TextTransform
|
||||
126
lua/text-transform/state.lua
Normal file
126
lua/text-transform/state.lua
Normal file
@@ -0,0 +1,126 @@
|
||||
local D = require("text-transform.utils.debug")
|
||||
|
||||
-- methods
|
||||
local TextTransform = {
|
||||
-- The current state of the plugin
|
||||
state = {
|
||||
-- A table containing cursor position and visual selection details,
|
||||
-- saved using `save_position()` and can be restored using `restore_positions()`
|
||||
--@type {buf: number, mode: string, pos: table, visual_start: table, visual_end: table}
|
||||
positions = {},
|
||||
},
|
||||
}
|
||||
|
||||
local function get_mode_type(mode)
|
||||
-- classify mode as either visual, line, block or normal
|
||||
local mode_map = {
|
||||
["v"] = "visual",
|
||||
["V"] = "line",
|
||||
["\22"] = "block",
|
||||
}
|
||||
return mode_map[mode] or "normal"
|
||||
end
|
||||
|
||||
function TextTransform.has_range(visual_start, visual_end)
|
||||
return visual_start and visual_end and visual_start[2] ~= visual_end[2]
|
||||
end
|
||||
|
||||
local function capture_part(start_sel, end_sel, return_type)
|
||||
local l, sel
|
||||
if return_type == "start" then
|
||||
l = math.min(start_sel[2], end_sel[2])
|
||||
sel = start_sel
|
||||
else
|
||||
l = math.max(start_sel[2], end_sel[2])
|
||||
sel = end_sel
|
||||
end
|
||||
return { sel[1], l, sel[3], sel[4] }
|
||||
end
|
||||
|
||||
function TextTransform.is_block_visual_mode()
|
||||
return TextTransform.state.positions.mode == "block"
|
||||
-- return vim.fn.mode() == "V" or vim.fn.mode() == "\22"
|
||||
end
|
||||
|
||||
function TextTransform.is_visual_mode()
|
||||
return TextTransform.state.positions.mode == "visual"
|
||||
-- return vim.fn.mode() == 'v'
|
||||
end
|
||||
|
||||
--- Save the current cursor position, mode, and visual selection ranges
|
||||
function TextTransform.save_positions()
|
||||
local buf = vim.api.nvim_get_current_buf()
|
||||
local mode_info = vim.api.nvim_get_mode()
|
||||
local mode = get_mode_type(mode_info.mode)
|
||||
local pos = vim.fn.getcurpos()
|
||||
-- leave mode, required to get the positions - they only register on mode leave
|
||||
-- in case of visual mode
|
||||
local esc = vim.api.nvim_replace_termcodes("<esc>", true, false, true)
|
||||
vim.api.nvim_feedkeys(esc, "x", true)
|
||||
local visual_start = vim.fn.getpos("'<")
|
||||
local visual_end = vim.fn.getpos("'>")
|
||||
D.log("save_positions", "Saved mode %s, cursor %s", mode, vim.inspect(pos))
|
||||
|
||||
if mode == "visual" or mode == "line" or mode == "block" then
|
||||
if TextTransform.has_range(visual_start, visual_end) then -- for ranges
|
||||
D.log(
|
||||
"save_positions",
|
||||
"Visual range, mode is %s, %s",
|
||||
mode,
|
||||
vim.inspect({ visual_start, visual_end })
|
||||
)
|
||||
-- Adjust the positions to correctly capture the entire block
|
||||
visual_start = capture_part(visual_start, visual_end, "start")
|
||||
visual_end = capture_part(visual_start, visual_end, "end")
|
||||
end
|
||||
D.log(
|
||||
"state",
|
||||
"Saved visual mode %s, cursor %s",
|
||||
mode,
|
||||
vim.inspect({ visual_start, visual_end })
|
||||
)
|
||||
end
|
||||
|
||||
local positions = {
|
||||
buf = buf,
|
||||
mode = mode,
|
||||
pos = pos,
|
||||
visual_start = visual_start,
|
||||
visual_end = visual_end,
|
||||
}
|
||||
|
||||
D.log("save_positions", "State: %s", vim.inspect(positions))
|
||||
TextTransform.state.positions = positions
|
||||
return positions
|
||||
end
|
||||
|
||||
--- Restore the cursor position, mode, and visual selection ranges saved using `save_position()`,
|
||||
--- or a given modified state, if passed as the first argument
|
||||
function TextTransform.restore_positions(positions)
|
||||
positions = positions or TextTransform.state.positions
|
||||
vim.api.nvim_set_current_buf(positions.buf)
|
||||
vim.fn.setpos(".", positions.pos)
|
||||
D.log(
|
||||
"restore_positions",
|
||||
"Restored mode %s, cursor %s",
|
||||
positions.mode,
|
||||
vim.inspect(positions.pos)
|
||||
)
|
||||
|
||||
-- Attempt to restore visual mode accurately
|
||||
if
|
||||
(positions.mode == "visual" or positions.mode == "block")
|
||||
and positions.visual_start
|
||||
and positions.visual_end
|
||||
then
|
||||
vim.fn.setpos("'<", positions.visual_start)
|
||||
vim.fn.setpos("'>", positions.visual_end)
|
||||
local command = "normal! gv"
|
||||
vim.cmd(command)
|
||||
D.log("restore_positions", [[Restored visual mode %s using "%s"]], positions.mode, command)
|
||||
end
|
||||
|
||||
TextTransform.state.positions = {}
|
||||
end
|
||||
|
||||
return TextTransform
|
||||
151
lua/text-transform/transformers.lua
Normal file
151
lua/text-transform/transformers.lua
Normal file
@@ -0,0 +1,151 @@
|
||||
local D = require("text-transform.utils.debug")
|
||||
-- local utils = require("text-transform.utils")
|
||||
|
||||
local TextTransform = {}
|
||||
|
||||
TextTransform.WORD_BOUNDRY = "[%_%-%s%.]"
|
||||
|
||||
--- Splits a string into words.
|
||||
---@param string string
|
||||
---@return table
|
||||
function TextTransform.to_words(string)
|
||||
local words = {}
|
||||
local word = ""
|
||||
local last_is_upper = false
|
||||
local last_is_digit = false
|
||||
for i = 1, #string do
|
||||
local char = string:sub(i, i)
|
||||
if char:match(TextTransform.WORD_BOUNDRY) then
|
||||
if word ~= "" then
|
||||
table.insert(words, word:lower())
|
||||
end
|
||||
word = ""
|
||||
else
|
||||
if
|
||||
(char:match("%d") and not last_is_digit)
|
||||
or (char:match("%u") and not last_is_upper and word ~= "")
|
||||
or (char:match("%l") and last_is_digit)
|
||||
then
|
||||
if word ~= "" then
|
||||
table.insert(words, word:lower())
|
||||
word = ""
|
||||
end
|
||||
end
|
||||
|
||||
-- Update flags based on current character type
|
||||
if char:match("%d") then
|
||||
last_is_digit = true
|
||||
last_is_upper = false
|
||||
elseif char:match("%u") then
|
||||
last_is_upper = true
|
||||
last_is_digit = false
|
||||
else -- Lowercase or any non-digit/non-uppercase
|
||||
last_is_upper = false
|
||||
last_is_digit = false
|
||||
end
|
||||
|
||||
-- Append current character to the current word
|
||||
word = word .. char
|
||||
end
|
||||
-- D.log("to_words", "i %d char %s word %s words %s", i, char, word, utils.dump(words))
|
||||
end
|
||||
if word ~= "" then
|
||||
table.insert(words, word:lower())
|
||||
end
|
||||
D.log("to_words", "words %s", vim.inspect(words))
|
||||
return words
|
||||
end
|
||||
|
||||
--- Transforms a table of strings into a string using a callback and separator.
|
||||
--- The callback is called with the word, the index, and the table of words.
|
||||
--- The separator is added between each word.
|
||||
---
|
||||
---@param words string|table string or table of strings
|
||||
---@param with_word_cb function (word: string, index: number, words: table) -> string
|
||||
---@param separator string|nil (optional)
|
||||
---@return string
|
||||
function TextTransform.transform_words(words, with_word_cb, separator)
|
||||
if type(words) ~= "table" then
|
||||
words = TextTransform.to_words(words)
|
||||
end
|
||||
local out = ""
|
||||
for i, word in ipairs(words) do
|
||||
local new_word = with_word_cb(word, i, word)
|
||||
if separator and i > 1 then
|
||||
new_word = separator .. new_word
|
||||
end
|
||||
out = out .. new_word
|
||||
D.log("transform_words", "word %s (%d) new_word %s out %s", word, i, new_word, out)
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
--- Transforms a string into camelCase.
|
||||
---@param string string
|
||||
---@return string
|
||||
function TextTransform.to_camel_case(string)
|
||||
return TextTransform.transform_words(string, function(word, i)
|
||||
if i == 1 then
|
||||
return word:lower()
|
||||
end
|
||||
return word:sub(1, 1):upper() .. word:sub(2):lower()
|
||||
end)
|
||||
end
|
||||
|
||||
--- Transfroms a string into snake_case.
|
||||
---@param string any
|
||||
---@return string
|
||||
function TextTransform.to_snake_case(string)
|
||||
return TextTransform.transform_words(string, function(word, i)
|
||||
if i == 1 then
|
||||
return word:lower()
|
||||
end
|
||||
return word:lower()
|
||||
end, "_")
|
||||
end
|
||||
|
||||
--- Transforms a string into PascalCase.
|
||||
---@param string string
|
||||
---@return string
|
||||
function TextTransform.to_pascal_case(string)
|
||||
local cc = TextTransform.to_camel_case(string)
|
||||
return cc:sub(1, 1):upper() .. cc:sub(2)
|
||||
end
|
||||
|
||||
--- Transforms a string into Title Case.
|
||||
---@param string string
|
||||
---@return string
|
||||
function TextTransform.to_title_case(string)
|
||||
return TextTransform.transform_words(string, function(word)
|
||||
return word:sub(1, 1):upper() .. word:sub(2):lower()
|
||||
end, " ")
|
||||
end
|
||||
|
||||
--- Transforms a string into kebab-case.
|
||||
---@param string string
|
||||
---@return string
|
||||
function TextTransform.to_kebab_case(string)
|
||||
return TextTransform.transform_words(string, function(word)
|
||||
return word:lower()
|
||||
end, "-")
|
||||
end
|
||||
|
||||
--- Transforms a string into dot.case.
|
||||
---@param string string
|
||||
---@return string
|
||||
function TextTransform.to_dot_case(string)
|
||||
return TextTransform.transform_words(string, function(word)
|
||||
return word:lower()
|
||||
end, ".")
|
||||
end
|
||||
|
||||
--- Transforms a string into CONSTANT_CASE.
|
||||
---@param string string
|
||||
---@return string
|
||||
function TextTransform.to_const_case(string)
|
||||
return TextTransform.transform_words(string, function(word)
|
||||
return word:upper()
|
||||
end, "_")
|
||||
end
|
||||
|
||||
return TextTransform
|
||||
@@ -1,13 +1,13 @@
|
||||
local D = {}
|
||||
|
||||
---prints only if debug is true.
|
||||
---
|
||||
---@param scope string: the scope from where this function is called.
|
||||
---@param str string: the formatted string.
|
||||
---@param ... any: the arguments of the formatted string.
|
||||
---@private
|
||||
local function is_debug()
|
||||
return _G.TextTransform ~= nil
|
||||
and _G.TextTransform.config ~= nil
|
||||
and _G.TextTransform.config.debug
|
||||
end
|
||||
|
||||
function D.log(scope, str, ...)
|
||||
if _G.TextTransform.config ~= nil and not _G.TextTransform.config.debug then
|
||||
if not is_debug() then
|
||||
return
|
||||
end
|
||||
|
||||
@@ -20,22 +20,17 @@ function D.log(scope, str, ...)
|
||||
|
||||
print(
|
||||
string.format(
|
||||
"[text-transform:%s %s in %s] > %s",
|
||||
"%s [text-transform:%s in %s] > %s",
|
||||
os.date("%H:%M:%S"),
|
||||
line,
|
||||
scope,
|
||||
line,
|
||||
string.format(str, ...)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
---prints the table if debug is true.
|
||||
---
|
||||
---@param table table: the table to print.
|
||||
---@param indent number?: the default indent value, starts at 0.
|
||||
---@private
|
||||
function D.tprint(table, indent)
|
||||
if _G.TextTransform.config ~= nil and not _G.TextTransform.config.debug then
|
||||
if not is_debug() then
|
||||
return
|
||||
end
|
||||
|
||||
19
lua/text-transform/utils/init.lua
Normal file
19
lua/text-transform/utils/init.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
local TextTransform = {}
|
||||
|
||||
--- Merges two tables into one. Same as `vim.tbl_extend("keep", t1, t2)`.
|
||||
--- Mutates the first table.
|
||||
---
|
||||
--- TODO accept multiple tables to merge
|
||||
---
|
||||
---@param t1 table
|
||||
---@param t2 table
|
||||
---@return table
|
||||
function TextTransform.merge(t1, t2)
|
||||
return vim.tbl_extend("force", t1, t2)
|
||||
end
|
||||
|
||||
function TextTransform.has_range(visual_start, visual_end)
|
||||
return visual_start and visual_end and visual_start[2] ~= visual_end[2]
|
||||
end
|
||||
|
||||
return TextTransform
|
||||
@@ -4,185 +4,3 @@ if _G.TextTransformLoaded then
|
||||
end
|
||||
|
||||
_G.TextTransformLoaded = true
|
||||
|
||||
function TextTransform.into_words(str)
|
||||
local words = {}
|
||||
local word = ""
|
||||
|
||||
local previous_is_upper = false
|
||||
for i = 1, #str do
|
||||
local char = str:sub(i, i)
|
||||
-- split on uppercase letters
|
||||
if char:match("%u") and not previous_is_upper then
|
||||
if word ~= "" then
|
||||
table.insert(words, word)
|
||||
end
|
||||
previous_is_upper = true
|
||||
word = char
|
||||
-- split on underscores, hyphens, and spaces
|
||||
elseif char:match("[%_%-%s]") then
|
||||
if word ~= "" then
|
||||
table.insert(words, word)
|
||||
previous_is_upper = false
|
||||
end
|
||||
word = ""
|
||||
else
|
||||
word = word .. char
|
||||
previous_is_upper = char:match("%u")
|
||||
end
|
||||
end
|
||||
if word ~= "" then
|
||||
table.insert(words, word)
|
||||
previous_is_upper = false
|
||||
end
|
||||
return words
|
||||
end
|
||||
|
||||
function TextTransform.camel_case(string)
|
||||
local words = TextTransform.into_words(string)
|
||||
local camel_case = ""
|
||||
for i, word in ipairs(words) do
|
||||
if i == 1 then
|
||||
camel_case = camel_case .. word:lower()
|
||||
else
|
||||
camel_case = camel_case .. word:sub(1, 1):upper() .. word:sub(2):lower()
|
||||
end
|
||||
end
|
||||
return camel_case
|
||||
end
|
||||
|
||||
function TextTransform.snake_case(string)
|
||||
local words = TextTransform.into_words(string)
|
||||
local snake_case = ""
|
||||
for i, word in ipairs(words) do
|
||||
if i == 1 then
|
||||
snake_case = snake_case .. word:lower()
|
||||
else
|
||||
snake_case = snake_case .. "_" .. word:lower()
|
||||
end
|
||||
end
|
||||
return snake_case
|
||||
end
|
||||
|
||||
function TextTransform.pascal_case(string)
|
||||
local words = TextTransform.into_words(string)
|
||||
local pascal_case = ""
|
||||
for _, word in ipairs(words) do
|
||||
pascal_case = pascal_case .. word:sub(1, 1):upper() .. word:sub(2):lower()
|
||||
end
|
||||
return pascal_case
|
||||
end
|
||||
|
||||
function TextTransform.kebab_case(string)
|
||||
local words = TextTransform.into_words(string)
|
||||
local kebab_case = ""
|
||||
for i, word in ipairs(words) do
|
||||
if i == 1 then
|
||||
kebab_case = kebab_case .. word:lower()
|
||||
else
|
||||
kebab_case = kebab_case .. "-" .. word:lower()
|
||||
end
|
||||
end
|
||||
return kebab_case
|
||||
end
|
||||
|
||||
function TextTransform.dot_case(string)
|
||||
local words = TextTransform.into_words(string)
|
||||
local dot_case = ""
|
||||
for i, word in ipairs(words) do
|
||||
if i == 1 then
|
||||
dot_case = dot_case .. word:lower()
|
||||
else
|
||||
dot_case = dot_case .. "." .. word:lower()
|
||||
end
|
||||
end
|
||||
return dot_case
|
||||
end
|
||||
|
||||
function TextTransform.title_case(string)
|
||||
local words = TextTransform.into_words(string)
|
||||
local title_case = ""
|
||||
for i, word in ipairs(words) do
|
||||
title_case = title_case .. word:sub(1, 1):upper() .. word:sub(2):lower()
|
||||
if i ~= #words then
|
||||
title_case = title_case .. " "
|
||||
end
|
||||
end
|
||||
return title_case
|
||||
end
|
||||
|
||||
function TextTransform.const_case(string)
|
||||
local words = TextTransform.into_words(string)
|
||||
local const_case = ""
|
||||
for i, word in ipairs(words) do
|
||||
if i == 1 then
|
||||
const_case = const_case .. word:upper()
|
||||
else
|
||||
const_case = const_case .. "_" .. word:upper()
|
||||
end
|
||||
end
|
||||
return const_case
|
||||
end
|
||||
|
||||
function TextTransform.replace_selection(transform)
|
||||
-- get the current visual selection, and transform the line, only replacing the selected text itself
|
||||
local _, start_line, start_col = unpack(vim.fn.getpos("'<"))
|
||||
local _, end_line, end_col = unpack(vim.fn.getpos("'>"))
|
||||
-- print(vim.inspect(vim.fn.getpos("'<")), vim.inspect(vim.fn.getpos("'>")),
|
||||
-- start_line, start_col, end_line, end_col)
|
||||
local lines = vim.fn.getline(start_line, end_line)
|
||||
-- print(vim.inspect(lines))
|
||||
|
||||
-- transform all included lines
|
||||
local transformed = ""
|
||||
|
||||
if #lines == 1 then
|
||||
transformed = lines[1]:sub(1, start_col - 1)
|
||||
.. transform(lines[1]:sub(start_col, end_col))
|
||||
.. lines[1]:sub(end_col + 1)
|
||||
else
|
||||
transformed = lines[1]:sub(1, start_col - 1) .. transform(lines[1]:sub(start_col)) .. "\n"
|
||||
for i = 2, #lines - 1 do
|
||||
transformed = transformed .. transform(lines[i]) .. "\n"
|
||||
end
|
||||
transformed = transformed
|
||||
.. transform(lines[#lines]:sub(1, end_col))
|
||||
.. lines[#lines]:sub(end_col + 1)
|
||||
end
|
||||
|
||||
-- replace the lines with the transformed lines
|
||||
vim.fn.setline(start_line, transformed)
|
||||
for i = start_line + 1, end_line do
|
||||
vim.fn.setline(i, "")
|
||||
end
|
||||
|
||||
-- move the cursor to the end of the transformed text
|
||||
vim.fn.cursor(end_line, end_col)
|
||||
end
|
||||
|
||||
function TextTransform.replace_word(transform)
|
||||
local word = vim.fn.expand("<cword>")
|
||||
local transformed = transform(word)
|
||||
vim.cmd("normal ciw" .. transformed)
|
||||
end
|
||||
|
||||
local should_test = false
|
||||
|
||||
if should_test then
|
||||
local map = {
|
||||
["CamelCase"] = TextTransform.camel_case,
|
||||
["SnakeCase"] = TextTransform.snake_case,
|
||||
["PascalCase"] = TextTransform.pascal_case,
|
||||
["KebabCase"] = TextTransform.kebab_case,
|
||||
["DotCase"] = TextTransform.dot_case,
|
||||
["TitleCase"] = TextTransform.title_case,
|
||||
["ConstCase"] = TextTransform.title_case,
|
||||
}
|
||||
|
||||
for k, tst in pairs(map) do
|
||||
print(k .. ": " .. "hello_world" .. " => " .. tst("hello_world"))
|
||||
print(k .. ": " .. "HELLO_WORLD" .. " => " .. tst("HELLO_WORLD"))
|
||||
print(k .. ": " .. "HelloWorld" .. " => " .. tst("HelloWorld"))
|
||||
print(k .. ": " .. "Hello-World" .. " => " .. tst("Hello-World"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,6 +6,8 @@ if #vim.api.nvim_list_uis() == 0 then
|
||||
-- Add 'mini.nvim' to 'runtimepath' to be able to use 'mini.test'
|
||||
-- Assumed that 'mini.nvim' is stored in 'deps/mini.nvim'
|
||||
vim.cmd("set rtp+=deps/mini.nvim")
|
||||
vim.cmd("set rtp+=deps/telescope.nvim")
|
||||
vim.cmd("set rtp+=deps/plenary.nvim")
|
||||
|
||||
-- Set up 'mini.test'
|
||||
require("mini.test").setup()
|
||||
|
||||
26
scripts/precommit.sh
Executable file
26
scripts/precommit.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2181,SC2086
|
||||
|
||||
# Stylua check
|
||||
diffs=$(stylua --check --output-format=json .)
|
||||
|
||||
# Exit code != 0 means there are changes (files are not formatted)
|
||||
if [[ "$?" -ne 0 ]]; then
|
||||
# Get filenames of diffs
|
||||
filelist="$(echo "$diffs" | jq -r '.file')"
|
||||
|
||||
# Format & add to git
|
||||
stylua $filelist
|
||||
git add $filelist
|
||||
fi
|
||||
|
||||
# Run lints
|
||||
make lint
|
||||
|
||||
# Run tests
|
||||
# make test
|
||||
|
||||
# Generate docs & add to git
|
||||
make documentation
|
||||
git add doc
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
USAGE="\033[0;37m[INFO] - usage: USERNAME=my-github-username PLUGIN_NAME=my-awesome-plugin REPOSITORY_NAME=my-awesome-plugin.nvim make setup\n\033[0m"
|
||||
|
||||
echo -e "$USAGE"
|
||||
|
||||
if [[ -z "$USERNAME" ]]; then
|
||||
echo -e "\t> No USERNAME provided, what's your GitHub/GitLab username?"
|
||||
read -r USERNAME
|
||||
fi
|
||||
|
||||
if [[ -z "$REPOSITORY_NAME" ]]; then
|
||||
REPOSITORY_NAME=$(basename -s .git "$(git config --get remote.origin.url)")
|
||||
|
||||
read -rp $'\t> No REPOSITORY_NAME provided, is \033[1;32m'"$REPOSITORY_NAME"$'\033[0m good? [Y/n]\n' yn
|
||||
case $yn in
|
||||
[Yy]* );;
|
||||
[Nn]* )
|
||||
echo -e "\t> Enter your repository name"
|
||||
read -r REPOSITORY_NAME
|
||||
;;
|
||||
* )
|
||||
echo -e "$USAGE"
|
||||
exit 1;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [[ -z "$PLUGIN_NAME" ]]; then
|
||||
DEFAULT_REPOSITORY_NAME=$(echo "$REPOSITORY_NAME" | sed -e "s/\.nvim//")
|
||||
read -rp $'\t> No PLUGIN_NAME provided, defaulting to \033[1;32m'"$DEFAULT_REPOSITORY_NAME"$'\033[0m, continue? [Y/n]\n' yn
|
||||
case $yn in
|
||||
[Yy]* )
|
||||
PLUGIN_NAME=$DEFAULT_REPOSITORY_NAME
|
||||
;;
|
||||
[Nn]* )
|
||||
echo -e "\t> Enter your plugin name"
|
||||
read -r PLUGIN_NAME
|
||||
;;
|
||||
* )
|
||||
echo -e "$USAGE"
|
||||
exit 1;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo -e "Username: \033[1;32m$USERNAME\033[0m\nRepository: \033[1;32m$REPOSITORY_NAME\033[0m\nPlugin: \033[1;32m$PLUGIN_NAME\033[0m\n\n\tRenaming placeholder files..."
|
||||
|
||||
rm -rf doc
|
||||
mv plugin/your-plugin-name.lua "plugin/$PLUGIN_NAME.lua"
|
||||
mv lua/your-plugin-name "lua/$PLUGIN_NAME"
|
||||
mv README_TEMPLATE.md README.md
|
||||
|
||||
echo -e "\tReplacing placeholder names..."
|
||||
|
||||
PASCAL_CASE_PLUGIN_NAME=$(echo "$PLUGIN_NAME" | perl -pe 's/(^|-)./uc($&)/ge;s/-//g')
|
||||
|
||||
grep -rl "YourPluginName" .github/ plugin/ tests/ lua/ | xargs sed -i "" -e "s/YourPluginName/$PASCAL_CASE_PLUGIN_NAME/g"
|
||||
grep -rl "your-plugin-name" README.md .github/ plugin/ tests/ lua/ | xargs sed -i "" -e "s/your-plugin-name/$PLUGIN_NAME/g"
|
||||
grep -rl "YOUR_GITHUB_USERNAME" README.md .github/ | xargs sed -i "" -e "s/YOUR_GITHUB_USERNAME/$USERNAME/g"
|
||||
grep -rl "YOUR_REPOSITORY_NAME" README.md .github/ | xargs sed -i "" -e "s/YOUR_REPOSITORY_NAME/$REPOSITORY_NAME/g"
|
||||
|
||||
echo -e "\n\033[1;32mOK.\033[0m"
|
||||
|
||||
echo -e "\tFetching dependencies (tests and documentation generator)..."
|
||||
|
||||
make deps
|
||||
|
||||
echo -e "\n\033[1;32mOK.\033[0m"
|
||||
|
||||
echo -e "\tGenerating docs..."
|
||||
|
||||
make documentation
|
||||
|
||||
echo -e "\n\033[1;32mOK.\033[0m"
|
||||
|
||||
echo -e "\tRunning tests..."
|
||||
|
||||
make test
|
||||
|
||||
echo -e "\n\033[1;32mOK.\033[0m"
|
||||
@@ -1,3 +1,4 @@
|
||||
local MiniTest = require("mini.test")
|
||||
-- partially imported from https://github.com/echasnovski/mini.nvim
|
||||
local Helpers = {}
|
||||
|
||||
@@ -162,4 +163,9 @@ Helpers.new_child_neovim = function()
|
||||
return child
|
||||
end
|
||||
|
||||
function Helpers.init_plugin(child, config)
|
||||
config = config or ""
|
||||
child.lua([[require('text-transform').setup(]] .. config .. [[)]])
|
||||
end
|
||||
|
||||
return Helpers
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
local helpers = dofile("tests/helpers.lua")
|
||||
local MiniTest = require("mini.test")
|
||||
|
||||
-- See https://github.com/echasnovski/mini.nvim/blob/main/lua/mini/test.lua for more documentation
|
||||
|
||||
@@ -31,28 +32,47 @@ T["setup()"]["sets exposed methods and default options value"] = function()
|
||||
-- global object that holds your plugin information
|
||||
eq_type_global(child, "_G.TextTransform", "table")
|
||||
|
||||
-- public methods
|
||||
eq_type_global(child, "_G.TextTransform.toggle", "function")
|
||||
eq_type_global(child, "_G.TextTransform.disable", "function")
|
||||
eq_type_global(child, "_G.TextTransform.enable", "function")
|
||||
|
||||
-- config
|
||||
eq_type_global(child, "_G.TextTransform.config", "table")
|
||||
|
||||
-- assert the value, and the type
|
||||
eq_config(child, "debug", false)
|
||||
eq_type_config(child, "debug", "boolean")
|
||||
eq_config(child, "debug", false)
|
||||
|
||||
eq_type_config(child, "keymap", "table")
|
||||
eq_type_config(child, "keymap.telescope_popup", "table")
|
||||
|
||||
eq_type_config(child, "keymap.telescope_popup.v", "string")
|
||||
eq_config(child, "keymap.telescope_popup.v", "<Leader>~")
|
||||
|
||||
eq_type_config(child, "keymap.telescope_popup.n", "string")
|
||||
eq_config(child, "keymap.telescope_popup.n", "<Leader>~")
|
||||
end
|
||||
|
||||
T["setup()"]["overrides default values"] = function()
|
||||
child.lua([[require('text-transform').setup({
|
||||
helpers.init_plugin(
|
||||
child,
|
||||
[[{
|
||||
-- write all the options with a value different than the default ones
|
||||
debug = true,
|
||||
})]])
|
||||
keymap = {
|
||||
["v"] = "<leader>c",
|
||||
["n"] = "<leader>c",
|
||||
},
|
||||
}]]
|
||||
)
|
||||
|
||||
-- assert the value, and the type
|
||||
eq_config(child, "debug", true)
|
||||
eq_type_config(child, "debug", "boolean")
|
||||
eq_config(child, "debug", true)
|
||||
|
||||
eq_type_config(child, "keymap", "table")
|
||||
|
||||
eq_type_config(child, "keymap.v", "string")
|
||||
eq_config(child, "keymap.v", "<leader>c")
|
||||
|
||||
eq_type_config(child, "keymap.n", "string")
|
||||
eq_config(child, "keymap.n", "<leader>c")
|
||||
end
|
||||
|
||||
return T
|
||||
63
tests/test_popups.lua
Normal file
63
tests/test_popups.lua
Normal file
@@ -0,0 +1,63 @@
|
||||
local helpers = dofile("tests/helpers.lua")
|
||||
local MiniTest = require("mini.test")
|
||||
|
||||
-- See https://github.com/echasnovski/mini.nvim/blob/main/lua/mini/test.lua for more documentation
|
||||
|
||||
local child = helpers.new_child_neovim()
|
||||
local eq_global, eq_config, eq_state =
|
||||
helpers.expect.global_equality, helpers.expect.config_equality, helpers.expect.state_equality
|
||||
local eq_type_global, eq_type_config, eq_type_state =
|
||||
helpers.expect.global_type_equality,
|
||||
helpers.expect.config_type_equality,
|
||||
helpers.expect.state_type_equality
|
||||
|
||||
local T = MiniTest.new_set({
|
||||
hooks = {
|
||||
-- This will be executed before every (even nested) case
|
||||
pre_case = function()
|
||||
-- Restart child process with custom 'init.lua' script
|
||||
child.restart({ "-u", "scripts/minimal_init.lua" })
|
||||
end,
|
||||
-- This will be executed one after all tests from this set are finished
|
||||
post_once = child.stop,
|
||||
},
|
||||
})
|
||||
|
||||
-- Tests related to the `setup` method.
|
||||
T["popups"] = MiniTest.new_set()
|
||||
|
||||
T["popups"]["exposes show_popup"] = function()
|
||||
helpers.init_plugin(child)
|
||||
|
||||
eq_type_global(child, "_G.TextTransform", "table")
|
||||
|
||||
eq_type_global(child, "_G.TextTransform.show_popup", "function")
|
||||
|
||||
eq_type_global(child, "_G.TextTransform.telescope_popup", "nil")
|
||||
end
|
||||
|
||||
T["popups"]["telescope exposes telescope_popup"] = function()
|
||||
helpers.init_plugin(child)
|
||||
|
||||
eq_type_global(child, "_G.TextTransform", "table")
|
||||
|
||||
eq_type_global(child, "_G.TextTransform.telescope_popup", "nil")
|
||||
|
||||
child.lua([[Telescope = require('text-transform.popup.telescope')]])
|
||||
|
||||
eq_type_global(child, "Telescope.telescope_popup", "function")
|
||||
end
|
||||
|
||||
T["popups"]["select exposes select_popup"] = function()
|
||||
helpers.init_plugin(child)
|
||||
|
||||
eq_type_global(child, "_G.TextTransform", "table")
|
||||
|
||||
eq_type_global(child, "_G.TextTransform.select_popup", "nil")
|
||||
|
||||
child.lua([[Select = require('text-transform.popup.select')]])
|
||||
|
||||
eq_type_global(child, "Select.select_popup", "function")
|
||||
end
|
||||
|
||||
return T
|
||||
69
tests/test_to_words.lua
Normal file
69
tests/test_to_words.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
local helpers = dofile("tests/helpers.lua")
|
||||
local MiniTest = require("mini.test")
|
||||
|
||||
-- See https://github.com/echasnovski/mini.nvim/blob/main/lua/mini/test.lua for more documentation
|
||||
|
||||
local child = helpers.new_child_neovim()
|
||||
local eq_global, eq_config, eq_state =
|
||||
helpers.expect.global_equality, helpers.expect.config_equality, helpers.expect.state_equality
|
||||
local eq_type_global, eq_type_config, eq_type_state =
|
||||
helpers.expect.global_type_equality,
|
||||
helpers.expect.config_type_equality,
|
||||
helpers.expect.state_type_equality
|
||||
|
||||
local T = MiniTest.new_set({
|
||||
hooks = {
|
||||
-- This will be executed before every (even nested) case
|
||||
pre_case = function()
|
||||
-- Restart child process with custom 'init.lua' script
|
||||
child.restart({ "-u", "scripts/minimal_init.lua" })
|
||||
end,
|
||||
-- This will be executed one after all tests from this set are finished
|
||||
post_once = child.stop,
|
||||
},
|
||||
})
|
||||
|
||||
local function test_string(child, str)
|
||||
helpers.init_plugin(child)
|
||||
child.lua([[result = require('text-transform').to_words("]] .. str .. [[")]])
|
||||
end
|
||||
|
||||
T["to_words()"] = MiniTest.new_set()
|
||||
|
||||
T["to_words()"]["should split normal spaced words"] = function()
|
||||
test_string(child, "hello world")
|
||||
eq_type_global(child, "result", "table")
|
||||
eq_global(child, "result", { "hello", "world" })
|
||||
end
|
||||
|
||||
T["to_words()"]["should split camel case strings"] = function()
|
||||
test_string(child, "helloWorld")
|
||||
eq_type_global(child, "result", "table")
|
||||
eq_global(child, "result", { "hello", "world" })
|
||||
end
|
||||
|
||||
T["to_words()"]["should split dot case strings"] = function()
|
||||
test_string(child, "hello.world")
|
||||
eq_type_global(child, "result", "table")
|
||||
eq_global(child, "result", { "hello", "world" })
|
||||
end
|
||||
|
||||
T["to_words()"]["should split const case strings"] = function()
|
||||
test_string(child, "HELLO_WORLD")
|
||||
eq_type_global(child, "result", "table")
|
||||
eq_global(child, "result", { "hello", "world" })
|
||||
end
|
||||
|
||||
T["to_words()"]["should treat numbers as words"] = function()
|
||||
test_string(child, "helloWorld123")
|
||||
eq_type_global(child, "result", "table")
|
||||
eq_global(child, "result", { "hello", "world", "123" })
|
||||
end
|
||||
|
||||
T["to_words()"]["should trim trailing/leading"] = function()
|
||||
test_string(child, " hello world ")
|
||||
eq_type_global(child, "result", "table")
|
||||
eq_global(child, "result", { "hello", "world" })
|
||||
end
|
||||
|
||||
return T
|
||||
107
tests/test_transforms.lua
Normal file
107
tests/test_transforms.lua
Normal file
@@ -0,0 +1,107 @@
|
||||
local helpers = dofile("tests/helpers.lua")
|
||||
|
||||
-- See https://github.com/echasnovski/mini.nvim/blob/main/lua/mini/test.lua for more documentation
|
||||
|
||||
local child = helpers.new_child_neovim()
|
||||
local eq_global, eq_config, eq_state =
|
||||
helpers.expect.global_equality, helpers.expect.config_equality, helpers.expect.state_equality
|
||||
local eq_type_global, eq_type_config, eq_type_state =
|
||||
helpers.expect.global_type_equality,
|
||||
helpers.expect.config_type_equality,
|
||||
helpers.expect.state_type_equality
|
||||
|
||||
local T = MiniTest.new_set({
|
||||
hooks = {
|
||||
-- This will be executed before every (even nested) case
|
||||
pre_case = function()
|
||||
-- Restart child process with custom 'init.lua' script
|
||||
child.restart({ "-u", "scripts/minimal_init.lua" })
|
||||
end,
|
||||
-- This will be executed one after all tests from this set are finished
|
||||
post_once = child.stop,
|
||||
},
|
||||
})
|
||||
|
||||
local function make_transform_test(fn_name, input, expected)
|
||||
return function()
|
||||
child.lua([[require('text-transform').setup()]])
|
||||
child.lua([[result = require('text-transform').to_]] .. fn_name .. '("' .. input .. '")')
|
||||
eq_global(child, "result", expected)
|
||||
end
|
||||
end
|
||||
|
||||
local map = {
|
||||
["camel_case"] = {
|
||||
{ "hello_world", "helloWorld" },
|
||||
{ "hello world", "helloWorld" },
|
||||
{ "hello-world", "helloWorld" },
|
||||
{ "hello.world", "helloWorld" },
|
||||
{ "hello", "hello" },
|
||||
{ "helloWorld123", "helloWorld123" },
|
||||
{ "HELLO_WORLD", "helloWorld" },
|
||||
},
|
||||
["snake_case"] = {
|
||||
{ "helloWorld", "hello_world" },
|
||||
{ "hello world", "hello_world" },
|
||||
{ "hello-world", "hello_world" },
|
||||
{ "hello.world", "hello_world" },
|
||||
{ "hello", "hello" },
|
||||
{ "helloWorld123", "hello_world_123" },
|
||||
{ "HELLO_WORLD", "hello_world" },
|
||||
},
|
||||
["pascal_case"] = {
|
||||
{ "hello_world", "HelloWorld" },
|
||||
{ "hello world", "HelloWorld" },
|
||||
{ "hello-world", "HelloWorld" },
|
||||
{ "hello.world", "HelloWorld" },
|
||||
{ "hello", "Hello" },
|
||||
{ "helloWorld123", "HelloWorld123" },
|
||||
{ "HELLO_WORLD", "HelloWorld" },
|
||||
},
|
||||
["kebab_case"] = {
|
||||
{ "helloWorld", "hello-world" },
|
||||
{ "hello world", "hello-world" },
|
||||
{ "hello-world", "hello-world" },
|
||||
{ "hello.world", "hello-world" },
|
||||
{ "hello", "hello" },
|
||||
{ "helloWorld123", "hello-world-123" },
|
||||
{ "HELLO_WORLD", "hello-world" },
|
||||
},
|
||||
["dot_case"] = {
|
||||
{ "helloWorld", "hello.world" },
|
||||
{ "hello world", "hello.world" },
|
||||
{ "hello-world", "hello.world" },
|
||||
{ "hello.world", "hello.world" },
|
||||
{ "hello", "hello" },
|
||||
{ "helloWorld123", "hello.world.123" },
|
||||
{ "HELLO_WORLD", "hello.world" },
|
||||
},
|
||||
["const_case"] = {
|
||||
{ "helloWorld", "HELLO_WORLD" },
|
||||
{ "hello world", "HELLO_WORLD" },
|
||||
{ "hello-world", "HELLO_WORLD" },
|
||||
{ "hello.world", "HELLO_WORLD" },
|
||||
{ "hello", "HELLO" },
|
||||
{ "helloWorld123", "HELLO_WORLD_123" },
|
||||
{ "HELLO_WORLD", "HELLO_WORLD" },
|
||||
},
|
||||
["title_case"] = {
|
||||
{ "helloWorld", "Hello World" },
|
||||
{ "hello world", "Hello World" },
|
||||
{ "hello-world", "Hello World" },
|
||||
{ "hello.world", "Hello World" },
|
||||
{ "hello", "Hello" },
|
||||
{ "helloWorld123", "Hello World 123" },
|
||||
{ "HELLO_WORLD", "Hello World" },
|
||||
},
|
||||
}
|
||||
|
||||
for fn_name, cases in pairs(map) do
|
||||
T[fn_name .. "()"] = MiniTest.new_set()
|
||||
for _, case in ipairs(cases) do
|
||||
local input, output = unpack(case)
|
||||
T[fn_name .. "()"]["input: " .. input] = make_transform_test(fn_name, input, output)
|
||||
end
|
||||
end
|
||||
|
||||
return T
|
||||
Reference in New Issue
Block a user