commit 45f1acb86f9be90cb5682f88530f27b63173074b
Author: Chen Asraf
Date: Mon May 15 02:09:42 2023 +0300
chore: setup
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..c1d757f
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,9 @@
+[*]
+tab_width = 2
+indent_size = 2
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..a52a73c
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,2 @@
+templates/
+scaffolds/
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..c38a05b
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @chenasraf
diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md
new file mode 100644
index 0000000..12315f0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Bug_report.md
@@ -0,0 +1,24 @@
+---
+name: Bug report
+about: It helps making the plugin more stable.
+---
+
+## Description
+
+
+
+## Steps to reproduce
+
+1. I did the command `...`
+2. Then I saw `...`
+3. Error
+
+## Expected behavior
+
+
+
+## Environment
+
+- Neovim version: [e.g. 0.5.x / 0.6.x / 0.7.x / 0.8.x / Nightly]
+- text-transform version: [e.g. latest / 0.1.2 / dev]
+- Plugin clash: [e.g. Telescope float window / lsp diagnostic]
diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md
new file mode 100644
index 0000000..8f8cf6c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/Feature_request.md
@@ -0,0 +1,13 @@
+---
+name: Feature request
+about: Suggest anything that would make your life easier, or the plugin better.
+---
+
+## Describe the problem
+
+
+
+## Describe the solution
+
+
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..656bf0c
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,7 @@
+## 📃 Summary
+
+
+
+## 📸 Preview
+
+
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..43a5ef9
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,102 @@
+name: Release
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ types: [opened, synchronize]
+
+concurrency:
+ group: github.head_ref
+ cancel-in-progress: true
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+ name: lint
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: JohnnyMorganz/stylua-action@v2
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ version: latest
+ args: --check .
+
+ documentation:
+ runs-on: ubuntu-latest
+ name: documentation
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 2
+
+ - name: setup neovim
+ uses: rhysd/action-setup-vim@v1
+ with:
+ neovim: true
+ version: v0.8.3
+
+ - name: generate documentation
+ run: make documentation-ci
+
+ - name: check docs diff
+ run: exit $(git status --porcelain doc | wc -l | tr -d " ")
+
+ # 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
+
+ # - 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: setup neovim
+ # uses: rhysd/action-setup-vim@v1
+ # with:
+ # neovim: true
+ # version: ${{ matrix.neovim_version }}
+
+ # - name: run tests
+ # run: make test-ci
+
+ release:
+ name: release
+ if: ${{ github.ref == 'refs/heads/master' }}
+ permissions: write-all
+ needs:
+ - lint
+ - documentation
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: google-github-actions/release-please-action@v3
+ id: release
+ with:
+ release-type: simple
+ package-name: text-transform.nvim
+
+ - name: tag stable versions
+ if: ${{ steps.release.outputs.release_created }}
+ run: |
+ git config user.name github-actions[bot]
+ git config user.email github-actions[bot]@users.noreply.github.com
+ git remote add gh-token "https://${{ secrets.GITHUB_TOKEN }}@github.com/google-github-actions/release-please-action.git"
+ git tag -d stable || true
+ git push origin :stable || true
+ git tag -a stable -m "Last Stable Release"
+ git push origin stable
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4b3caad
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+deps
+**.DS_Store
+.luarc.json
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..a52a73c
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,2 @@
+templates/
+scaffolds/
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..548c817
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,15 @@
+{
+ "printWidth": 100,
+ "semi": false,
+ "singleQuote": true,
+ "trailingComma": "all",
+ "overrides": [
+ {
+ "files": "*.md",
+ "options": {
+ "printWidth": 100,
+ "proseWrap": "always"
+ }
+ }
+ ]
+}
diff --git a/.styluaignore b/.styluaignore
new file mode 100644
index 0000000..c7f3cb4
--- /dev/null
+++ b/.styluaignore
@@ -0,0 +1,2 @@
+deps/
+**/mini/
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..4dc68c6
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,2 @@
+# Changelog
+
diff --git a/FUNDING.yml b/FUNDING.yml
new file mode 100644
index 0000000..c665b77
--- /dev/null
+++ b/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: chenasraf
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: casraf
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+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"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8ff8382
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Chen Asraf
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..33820ec
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,34 @@
+# we disable the `all` command because some external tool might run it automatically
+.SUFFIXES:
+
+all:
+
+# runs all the test files.
+test:
+ nvim --version | head -n 1 && echo ''
+ nvim --headless --noplugin -u ./scripts/minimal_init.lua \
+ -c "lua require('mini.test').setup()" \
+ -c "lua MiniTest.run({ execute = { reporter = MiniTest.gen_reporter.stdout({ group_depth = 1 }) } })"
+
+# installs `mini.nvim`, used for both the tests and documentation.
+deps:
+ @mkdir -p deps
+ git clone --depth 1 https://github.com/echasnovski/mini.nvim deps/mini.nvim
+
+# installs deps before running tests, useful for the CI.
+test-ci: deps test
+
+# generates the documentation.
+documentation:
+ nvim --headless --noplugin -u ./scripts/minimal_init.lua -c "lua require('mini.doc').generate()" -c "qa!"
+
+# installs deps before running the documentation generation, useful for the CI.
+documentation-ci: deps documentation
+
+# performs a lint check and fixes issue if possible, following the config in `stylua.toml`.
+lint:
+ stylua .
+
+# setup
+setup:
+ ./scripts/setup.sh
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4e2ba62
--- /dev/null
+++ b/README.md
@@ -0,0 +1,132 @@
+
+
text-transform.nvim
+
+
+
+ > A catch phrase that describes your plugin.
+
+
+
+ > Drag your video (<10MB) here to host it for free on GitHub.
+
+
+
+
+> Videos don't work on GitHub mobile, so a GIF alternative can help users.
+
+_[GIF version of the showcase video for mobile users](SHOWCASE_GIF_LINK)_
+
+
+
+## ⚡️ Features
+
+> Write short sentences describing your plugin features
+
+- FEATURE 1
+- FEATURE ..
+- FEATURE N
+
+## 📋 Installation
+
+
+
+
+
+| Package manager |
+Snippet |
+
+
+
+
+|
+
+[wbthomason/packer.nvim](https://github.com/wbthomason/packer.nvim)
+
+ |
+
+
+```lua
+-- stable version
+use {"text-transform.nvim", tag = "*" }
+-- dev version
+use {"text-transform.nvim"}
+```
+
+ |
+
+
+|
+
+[junegunn/vim-plug](https://github.com/junegunn/vim-plug)
+
+ |
+
+
+```lua
+-- stable version
+Plug "text-transform.nvim", { "tag": "*" }
+-- dev version
+Plug "text-transform.nvim"
+```
+
+ |
+
+
+|
+
+[folke/lazy.nvim](https://github.com/folke/lazy.nvim)
+
+ |
+
+
+```lua
+-- stable version
+require("lazy").setup({{"text-transform.nvim", version = "*"}})
+-- dev version
+require("lazy").setup({"text-transform.nvim"})
+```
+
+ |
+
+
+
+
+
+## ☄ Getting started
+
+> Describe how to use the plugin the simplest way
+
+## ⚙ Configuration
+
+> The configuration list sometimes become cumbersome, making it folded by default reduce the noise of the README file.
+
+
+Click to unfold the full list of options with their default values
+
+> **Note**: The options are also available in Neovim by calling `:h text-transform.options`
+
+```lua
+require("text-transform").setup({
+ -- you can copy the full list from lua/text-transform/config.lua
+})
+```
+
+
+
+## 🧰 Commands
+
+| Command | Description |
+|-------------|----------------------------|
+| `:Toggle` | Enables the plugin. |
+
+## ⌨ Contributing
+
+PRs and issues are always welcome. Make sure to provide as much context as possible when opening one.
+
+## 🗞 Wiki
+
+You can find guides and showcase of the plugin on [the Wiki](https://github.com/chenasraf/text-transform.nvim/wiki)
+
+## 🎭 Motivations
+
+> If alternatives of your plugin exist, you can provide some pros/cons of using yours over the others.
diff --git a/doc/tags b/doc/tags
new file mode 100644
index 0000000..9a3781a
--- /dev/null
+++ b/doc/tags
@@ -0,0 +1,2 @@
+TextTransform.options text-transform.txt /*TextTransform.options*
+TextTransform.setup() text-transform.txt /*TextTransform.setup()*
diff --git a/doc/text-transform.txt b/doc/text-transform.txt
new file mode 100644
index 0000000..9436a23
--- /dev/null
+++ b/doc/text-transform.txt
@@ -0,0 +1,31 @@
+==============================================================================
+------------------------------------------------------------------------------
+ *TextTransform.options*
+ `TextTransform.options`
+Your plugin configuration with its default values.
+
+Default values:
+>
+ TextTransform.options = {
+ -- Prints useful logs about what event are triggered, and reasons actions are executed.
+ debug = false,
+ keymap = {
+ "~",
+ },
+ }
+
+<
+
+------------------------------------------------------------------------------
+ *TextTransform.setup()*
+ `TextTransform.setup`({options})
+Define your text-transform setup.
+
+Parameters~
+{options} `(table)` Module config table. See |TextTransform.options|.
+
+Usage~
+`require("text-transform").setup()` (add `{}` with your |TextTransform.options| table)
+
+
+ vim:tw=78:ts=8:noet:ft=help:norl:
\ No newline at end of file
diff --git a/lua/text-transform/config.lua b/lua/text-transform/config.lua
new file mode 100644
index 0000000..0f34dfd
--- /dev/null
+++ b/lua/text-transform/config.lua
@@ -0,0 +1,28 @@
+local TextTransform = {}
+
+--- 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.
+ debug = false,
+ keymap = {
+ "~",
+ },
+}
+
+--- Define your text-transform setup.
+---
+---@param options table Module config table. See |TextTransform.options|.
+---
+---@usage `require("text-transform").setup()` (add `{}` with your |TextTransform.options| table)
+function TextTransform.setup(options)
+ options = options or {}
+
+ TextTransform.options = vim.tbl_deep_extend("keep", options, TextTransform.options)
+
+ return TextTransform.options
+end
+
+return TextTransform
diff --git a/lua/text-transform/init.lua b/lua/text-transform/init.lua
new file mode 100644
index 0000000..8441a50
--- /dev/null
+++ b/lua/text-transform/init.lua
@@ -0,0 +1,41 @@
+local M = require("text-transform.main")
+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
+
+return _G.TextTransform
diff --git a/lua/text-transform/main.lua b/lua/text-transform/main.lua
new file mode 100644
index 0000000..57b8a49
--- /dev/null
+++ b/lua/text-transform/main.lua
@@ -0,0 +1,49 @@
+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
diff --git a/lua/text-transform/util/debug.lua b/lua/text-transform/util/debug.lua
new file mode 100644
index 0000000..3347dec
--- /dev/null
+++ b/lua/text-transform/util/debug.lua
@@ -0,0 +1,61 @@
+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
+function D.log(scope, str, ...)
+ if _G.TextTransform.config ~= nil and not _G.TextTransform.config.debug then
+ return
+ end
+
+ local info = debug.getinfo(2, "Sl")
+ local line = ""
+
+ if info then
+ line = "L" .. info.currentline
+ end
+
+ print(
+ string.format(
+ "[text-transform:%s %s in %s] > %s",
+ os.date("%H:%M:%S"),
+ line,
+ scope,
+ 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
+ return
+ end
+
+ if not indent then
+ indent = 0
+ end
+
+ for k, v in pairs(table) do
+ local formatting = string.rep(" ", indent) .. k .. ": "
+ if type(v) == "table" then
+ print(formatting)
+ D.tprint(v, indent + 1)
+ elseif type(v) == "boolean" then
+ print(formatting .. tostring(v))
+ elseif type(v) == "function" then
+ print(formatting .. "FUNCTION")
+ else
+ print(formatting .. v)
+ end
+ end
+end
+
+return D
diff --git a/plugin/text-transform.lua b/plugin/text-transform.lua
new file mode 100644
index 0000000..64700a7
--- /dev/null
+++ b/plugin/text-transform.lua
@@ -0,0 +1,164 @@
+-- You can use this loaded variable to enable conditional parts of your plugin.
+if _G.TextTransformLoaded then
+ return
+end
+
+_G.TextTransformLoaded = true
+
+local function 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 IntoWords(string)
+ print(vim.inspect(into_words(string)))
+end
+
+function CamelCase(string)
+ local words = 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 SnakeCase(string)
+ local words = 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 PascalCase(string)
+ local words = 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 KebabCase(string)
+ local words = 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 DotCase(string)
+ local words = 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 TitleCase(string)
+ local words = 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 ReplaceCurrentSelection(transform)
+ local selection = vim.fn.getline("'<", "'>")
+ local transformed = transform(selection)
+ vim.fn.setline("'<", transformed)
+end
+
+function ReplaceCurrentWord(transform)
+ local word = vim.fn.expand("")
+ local transformed = transform(word)
+ vim.cmd("normal ciw" .. transformed)
+end
+
+local should_test = false
+
+if should_test then
+ local map = {
+ ["CamelCase"] = CamelCase,
+ ["SnakeCase"] = SnakeCase,
+ ["PascalCase"] = PascalCase,
+ ["KebabCase"] = KebabCase,
+ ["DotCase"] = DotCase,
+ ["TitleCase"] = TitleCase,
+ }
+
+ 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
+-- use input from current word in editor
+vim.cmd("amenu Transforms.&camelCase :lua ReplaceCurrentWord(CamelCase)")
+vim.cmd("amenu Transforms.&snake_case :lua ReplaceCurrentWord(SnakeCase)")
+vim.cmd("amenu Transforms.&PascalCase :lua ReplaceCurrentWord(PascalCase)")
+vim.cmd("amenu Transforms.&kebab-case :lua ReplaceCurrentWord(KebabCase)")
+vim.cmd("amenu Transforms.&dot\\.case :lua ReplaceCurrentWord(DotCase)")
+vim.cmd("amenu Transforms.&Title\\ Case :lua ReplaceCurrentWord(TitleCase)")
+
+for i in TextTransform.config.keymap do
+ vim.keymap.set(
+ { "n", "v" },
+ _G.TextTransform.config.keymap[i],
+ "popup Transforms",
+ { silent = true }
+ )
+end
diff --git a/scripts/minimal_init.lua b/scripts/minimal_init.lua
new file mode 100644
index 0000000..362995b
--- /dev/null
+++ b/scripts/minimal_init.lua
@@ -0,0 +1,15 @@
+-- Add current directory to 'runtimepath' to be able to use 'lua' files
+vim.cmd([[let &rtp.=','.getcwd()]])
+
+-- Set up 'mini.test' and 'mini.doc' only when calling headless Neovim (like with `make test` or `make documentation`)
+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")
+
+ -- Set up 'mini.test'
+ require("mini.test").setup()
+
+ -- Set up 'mini.doc'
+ require("mini.doc").setup()
+end
diff --git a/scripts/setup.sh b/scripts/setup.sh
new file mode 100755
index 0000000..2695c62
--- /dev/null
+++ b/scripts/setup.sh
@@ -0,0 +1,79 @@
+#!/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 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 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 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"
diff --git a/stylua.toml b/stylua.toml
new file mode 100644
index 0000000..6376ab8
--- /dev/null
+++ b/stylua.toml
@@ -0,0 +1,5 @@
+indent_type = "Spaces"
+indent_width = 4
+column_width = 100
+quote_style = "AutoPreferDouble"
+no_call_parentheses = false
diff --git a/tests/helpers.lua b/tests/helpers.lua
new file mode 100644
index 0000000..d34828e
--- /dev/null
+++ b/tests/helpers.lua
@@ -0,0 +1,166 @@
+-- partially imported from https://github.com/echasnovski/mini.nvim
+local Helpers = {}
+
+-- Add extra expectations
+Helpers.expect = vim.deepcopy(MiniTest.expect)
+
+-- The error message returned when a test fails.
+local function errorMessage(str, pattern)
+ return string.format("Pattern: %s\nObserved string: %s", vim.inspect(pattern), str)
+end
+
+-- Check equality of a global `field` against `value` in the given `child` process.
+-- @usage global_equality(child, "_G.TextTransformLoaded", true)
+Helpers.expect.global_equality = MiniTest.new_expectation(
+ "variable in child process matches",
+ function(child, field, value)
+ return Helpers.expect.equality(child.lua_get(field), value)
+ end,
+ errorMessage
+)
+
+-- Check type equality of a global `field` against `value` in the given `child` process.
+-- @usage global_type_equality(child, "_G.TextTransformLoaded", "boolean")
+Helpers.expect.global_type_equality = MiniTest.new_expectation(
+ "variable type in child process matches",
+ function(child, field, value)
+ return Helpers.expect.global_equality(child, "type(" .. field .. ")", value)
+ end,
+ errorMessage
+)
+
+-- Check equality of a config `field` against `value` in the given `child` process.
+-- @usage option_equality(child, "debug", true)
+Helpers.expect.config_equality = MiniTest.new_expectation(
+ "config option matches",
+ function(child, field, value)
+ return Helpers.expect.global_equality(child, "_G.TextTransform.config." .. field, value)
+ end,
+ errorMessage
+)
+
+-- Check type equality of a config `field` against `value` in the given `child` process.
+-- @usage config_type_equality(child, "debug", "boolean")
+Helpers.expect.config_type_equality = MiniTest.new_expectation(
+ "config option type matches",
+ function(child, field, value)
+ return Helpers.expect.global_equality(
+ child,
+ "type(_G.TextTransform.config." .. field .. ")",
+ value
+ )
+ end,
+ errorMessage
+)
+
+-- Check equality of a state `field` against `value` in the given `child` process.
+-- @usage state_equality(child, "enabled", true)
+Helpers.expect.state_equality = MiniTest.new_expectation(
+ "state matches",
+ function(child, field, value)
+ return Helpers.expect.global_equality(child, "_G.TextTransform.enabled." .. field, value)
+ end,
+ errorMessage
+)
+
+-- Check type equality of a state `field` against `value` in the given `child` process.
+-- @usage state_type_equality(child, "enabled", "boolean")
+Helpers.expect.state_type_equality = MiniTest.new_expectation(
+ "state type matches",
+ function(child, field, value)
+ return Helpers.expect.global_equality(
+ child,
+ "type(_G.TextTransform.state." .. field .. ")",
+ value
+ )
+ end,
+ errorMessage
+)
+
+Helpers.expect.match = MiniTest.new_expectation("string matching", function(str, pattern)
+ return str:find(pattern) ~= nil
+end, errorMessage)
+
+Helpers.expect.no_match = MiniTest.new_expectation("no string matching", function(str, pattern)
+ return str:find(pattern) == nil
+end, errorMessage)
+
+-- Monkey-patch `MiniTest.new_child_neovim` with helpful wrappers
+Helpers.new_child_neovim = function()
+ local child = MiniTest.new_child_neovim()
+
+ local prevent_hanging = function(method)
+ -- stylua: ignore
+ if not child.is_blocked() then return end
+
+ local msg =
+ string.format("Can not use `child.%s` because child process is blocked.", method)
+ error(msg)
+ end
+
+ child.setup = function()
+ child.restart({ "-u", "scripts/minimal_init.lua" })
+
+ -- Change initial buffer to be readonly. This not only increases execution
+ -- speed, but more closely resembles manually opened Neovim.
+ child.bo.readonly = false
+ end
+
+ child.set_lines = function(arr, start, finish)
+ prevent_hanging("set_lines")
+
+ if type(arr) == "string" then
+ arr = vim.split(arr, "\n")
+ end
+
+ child.api.nvim_buf_set_lines(0, start or 0, finish or -1, false, arr)
+ end
+
+ child.get_lines = function(start, finish)
+ prevent_hanging("get_lines")
+
+ return child.api.nvim_buf_get_lines(0, start or 0, finish or -1, false)
+ end
+
+ child.set_cursor = function(line, column, win_id)
+ prevent_hanging("set_cursor")
+
+ child.api.nvim_win_set_cursor(win_id or 0, { line, column })
+ end
+
+ child.get_cursor = function(win_id)
+ prevent_hanging("get_cursor")
+
+ return child.api.nvim_win_get_cursor(win_id or 0)
+ end
+
+ child.set_size = function(lines, columns)
+ prevent_hanging("set_size")
+
+ if type(lines) == "number" then
+ child.o.lines = lines
+ end
+
+ if type(columns) == "number" then
+ child.o.columns = columns
+ end
+ end
+
+ child.get_size = function()
+ prevent_hanging("get_size")
+
+ return { child.o.lines, child.o.columns }
+ end
+
+ child.expect_screenshot = function(opts, path, screenshot_opts)
+ if child.fn.has("nvim-0.8") == 0 then
+ MiniTest.skip("Screenshots are tested for Neovim>=0.8 (for simplicity).")
+ end
+
+ MiniTest.expect.reference_screenshot(child.get_screenshot(screenshot_opts), path, opts)
+ end
+
+ return child
+end
+
+return Helpers
diff --git a/tests/test_API.lua b/tests/test_API.lua
new file mode 100644
index 0000000..01193a4
--- /dev/null
+++ b/tests/test_API.lua
@@ -0,0 +1,58 @@
+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,
+ },
+})
+
+-- Tests related to the `setup` method.
+T["setup()"] = MiniTest.new_set()
+
+T["setup()"]["sets exposed methods and default options value"] = function()
+ child.lua([[require('text-transform').setup()]])
+
+ -- 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")
+end
+
+T["setup()"]["overrides default values"] = function()
+ child.lua([[require('text-transform').setup({
+ -- write all the options with a value different than the default ones
+ debug = true,
+ })]])
+
+ -- assert the value, and the type
+ eq_config(child, "debug", true)
+ eq_type_config(child, "debug", "boolean")
+end
+
+return T