Compare commits

...

7 Commits

Author SHA1 Message Date
Yussef Dalton
4efb28c21d
Merge c54af24ea921fed3d21a7f3eee009d79400c6fc1 into 965e8f905e9f1db5ce0b5e74329acf523cad464a 2024-05-13 09:48:27 -05:00
965e8f905e
test: overhaul test setup and make commands 2024-05-13 09:47:27 -05:00
04089f0b7d
refactor: migrate plugin/ file to lua from vimscript 2024-05-13 05:02:17 -05:00
34f6d24007
style: format with stylua 2024-05-13 04:57:23 -05:00
bc8dea7a78
fix(svelte): use correct close tag patterns
See https://github.com/windwp/nvim-ts-autotag/pull/167

Co-authored-by: "roy.crippen4" <roy.crippen4@archarithms.com>
2024-05-13 04:37:33 -05:00
Léo DEVILLE
6bf91cad7e
Add twig filetype
See https://github.com/windwp/nvim-ts-autotag/pull/169

Signed-off-by: Price Hiller <price@orion-technologies.io>
Co-authored-by: Ystri0n <164430108+Ystri0n@users.noreply.github.com>
2024-05-13 04:36:54 -05:00
629011167b
docs: use correct option: skip_tags -> skip_tag
See https://github.com/windwp/nvim-ts-autotag/pull/170

Co-authored-by: nicoqh <nicoqh@gmail.com>
2024-05-13 04:35:59 -05:00
21 changed files with 913 additions and 736 deletions

1
.gitignore vendored
View File

@ -0,0 +1 @@
tests/.deps

View File

@ -1,2 +1,8 @@
clean:
nvim --headless --clean -n -c "lua vim.fn.delete('./tests/.deps', 'rf')" +q
test:
nvim --headless --noplugin -u tests/minimal.vim -c "PlenaryBustedDirectory tests/ {minimal_init = 'tests/minimal.vim'}"
nvim --headless --clean -u tests/test.lua "$(FILE)"
lint:
stylua --check lua/ tests/
format:
stylua lua/ tests/

View File

@ -15,6 +15,7 @@ It works with:
- rescript
- svelte
- tsx
- twig
- typescript
- vue
- xml
@ -75,9 +76,9 @@ local filetypes = {
'xml',
'php',
'markdown',
'astro', 'glimmer', 'handlebars', 'hbs'
'astro', 'glimmer', 'handlebars', 'hbs', 'twig'
}
local skip_tags = {
local skip_tag = {
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'slot',
'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr','menuitem'
}

View File

@ -3,23 +3,25 @@ local internal = require("nvim-ts-autotag.internal")
local M = {}
function M.init()
require "nvim-treesitter".define_modules {
autotag = {
module_path = 'nvim-ts-autotag.internal',
is_supported = function(lang)
return internal.is_supported(lang)
end
}
}
require("nvim-treesitter").define_modules({
autotag = {
module_path = "nvim-ts-autotag.internal",
is_supported = function(lang)
return internal.is_supported(lang)
end,
},
})
end
function M.ensure_ts_parsers_installed() end
function M.setup(opts)
internal.setup(opts)
vim.cmd[[augroup nvim_ts_xmltag]]
vim.cmd[[autocmd!]]
vim.cmd[[autocmd FileType * call v:lua.require('nvim-ts-autotag.internal').attach()]]
vim.cmd[[autocmd BufDelete * lua require('nvim-ts-autotag.internal').detach(vim.fn.expand('<abuf>'))]]
vim.cmd[[augroup end]]
internal.setup(opts)
vim.cmd([[augroup nvim_ts_xmltag]])
vim.cmd([[autocmd!]])
vim.cmd([[autocmd FileType * call v:lua.require('nvim-ts-autotag.internal').attach()]])
vim.cmd([[autocmd BufDelete * lua require('nvim-ts-autotag.internal').detach(vim.fn.expand('<abuf>'))]])
vim.cmd([[augroup end]])
end
return M

View File

@ -1,13 +1,12 @@
if _G.__is_log then
return require('plenary.log').new {
plugin = 'nvim-ts-autotag',
level = (_G.__is_log == true and 'debug') or 'warn',
}
return require("plenary.log").new({
plugin = "nvim-ts-autotag",
level = (_G.__is_log == true and "debug") or "warn",
})
else
return{
return {
debug = function(_) end,
info = function(_) end,
error = function(_) end,
}
end

View File

@ -12,7 +12,7 @@ M.tbl_filetypes = {
'xml',
'php',
'markdown',
'astro', 'glimmer', 'handlebars', 'hbs',
'astro', 'glimmer', 'handlebars', 'hbs', 'twig',
'htmldjango',
'eruby',
'templ',
@ -33,6 +33,7 @@ local HTML_TAG = {
'htmldjango',
'markdown',
'php',
'twig',
'xml',
'blade',
},
@ -87,8 +88,8 @@ local SVELTE_TAG = {
start_name_tag_pattern = { 'tag_name' },
end_tag_pattern = { 'end_tag' },
end_name_tag_pattern = { 'tag_name' },
close_tag_pattern = { 'ERROR' },
close_name_tag_pattern = { 'ERROR', 'erroneous_end_tag_name' },
close_tag_pattern = { 'erroneous_end_tag' },
close_name_tag_pattern = { 'erroneous_end_tag_name' },
element_tag = { 'element' },
skip_tag_pattern = { 'quoted_attribute_value', 'end_tag' },
}
@ -486,8 +487,8 @@ local function rename_start_tag()
-- log.debug("do replace")
-- log.debug(tag_name)
-- log.debug(close_tag_name)
if close_tag_name == '>' then
tag_name = tag_name .. '>'
if close_tag_name == ">" then
tag_name = tag_name .. ">"
end
replace_text_node(close_tag_node, tag_name)
end
@ -532,7 +533,7 @@ local function rename_end_tag()
if start_tag_node ~= nil then
local start_tag_name = get_tag_name(start_tag_node)
if tag_name ~= start_tag_name then
log.debug('replace end tag')
log.debug("replace end tag")
replace_text_node(start_tag_node, tag_name)
end
end
@ -551,8 +552,8 @@ local function is_before(regex, range)
end
end
local is_before_word = is_before('%w', 1)
local is_before_arrow = is_before('<', 0)
local is_before_word = is_before("%w", 1)
local is_before_arrow = is_before("<", 0)
M.rename_tag = function()
if is_before_word() and parsers.has_parser() then
@ -569,7 +570,7 @@ M.attach = function(bufnr, lang)
if is_in_table(M.tbl_filetypes, vim.bo.filetype) then
setup_ts_tag()
local group = vim.api.nvim_create_augroup('nvim-ts-autotag', { clear = true })
local group = vim.api.nvim_create_augroup("nvim-ts-autotag", { clear = true })
if M.enable_close == true then
vim.api.nvim_buf_set_keymap(bufnr or 0, "i", ">", ">", {
noremap = true,
@ -590,7 +591,7 @@ M.attach = function(bufnr, lang)
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
vim.api.nvim_buf_set_text(bufnr or 0, row - 1, col, row - 1, col, { "/" })
if is_before_arrow() then
log.debug('is_before_arrow')
log.debug("is_before_arrow")
M.close_slash_tag()
end
local new_row, new_col = unpack(vim.api.nvim_win_get_cursor(0))

View File

@ -1,19 +1,16 @@
local _, ts_utils = pcall(require, 'nvim-treesitter.ts_utils')
local log = require('nvim-ts-autotag._log')
local _, ts_utils = pcall(require, "nvim-treesitter.ts_utils")
local log = require("nvim-ts-autotag._log")
local get_node_text = vim.treesitter.get_node_text or vim.treesitter.query.get_node_text or ts_utils.get_node_text
local M = {}
M.get_node_text = function(node)
local _, txt = pcall(get_node_text, node, vim.api.nvim_get_current_buf())
return vim.split(txt, '\n') or {}
return vim.split(txt, "\n") or {}
end
M.verify_node = function(node, node_tag)
local txt = get_node_text(node, vim.api.nvim_get_current_buf())
if
txt:match(string.format('^<%s>', node_tag))
and txt:match(string.format('</%s>$', node_tag))
then
if txt:match(string.format("^<%s>", node_tag)) and txt:match(string.format("</%s>$", node_tag)) then
return true
end
return false
@ -30,22 +27,22 @@ M.dump_node = function(node)
end
M.is_close_empty_node = function(node)
local tag_name = ''
local tag_name = ""
if node ~= nil then
local text = M.get_node_text(node)
tag_name = text[#text - 1]
end
return tag_name:match('%<%/%>$')
return tag_name:match("%<%/%>$")
end
M.dump_node_text = function(target)
log.debug('=============================')
log.debug("=============================")
for node in target:iter_children() do
local node_type = node:type()
local text = M.get_node_text(node)
log.debug('type:' .. node_type .. ' ')
log.debug("type:" .. node_type .. " ")
log.debug(text)
end
log.debug('=============================')
log.debug("=============================")
end
return M

View File

@ -0,0 +1 @@
require("nvim-ts-autotag").init()

View File

@ -1 +0,0 @@
lua require "nvim-ts-autotag".init()

6
tests/.luarc.json Normal file
View File

@ -0,0 +1,6 @@
{
"diagnostics.globals": [
"it",
"describe"
]
}

View File

@ -1,41 +0,0 @@
set rtp +=.
set rtp +=../plenary.nvim/
set rtp +=../nvim-treesitter/
set rtp +=../playground/
set rtp +=../nvim-treesitter-rescript/
runtime! plugin/plenary.vim
runtime! plugin/nvim-treesitter.lua
runtime! plugin/nvim-treesitter-playground.lua
runtime! plugin/nvim-treesitter-rescript.vim
set noswapfile
set nobackup
filetype indent off
set nowritebackup
set noautoindent
set nocindent
set nosmartindent
set indentexpr=
set foldlevel=9999
lua << EOF
_G.__is_log=true
_G.ts_filetypes = {
'html', 'javascript', 'typescript', 'svelte', 'vue', 'tsx', 'php', 'glimmer', 'rescript', 'embedded_template'
}
require("plenary/busted")
vim.cmd[[luafile ./tests/test-utils.lua]]
require("nvim-ts-autotag").setup({
enable = true,
enable_rename = true,
enable_close = true,
enable_close_on_slash = true,
})
EOF

111
tests/minimal_init.lua Normal file
View File

@ -0,0 +1,111 @@
local M = {}
local utils = require("tests.utils.utils")
local root = utils.paths.Root:push(".deps/")
---@class MinPlugin A plugin to download and register on the package path
---@alias PluginName string The plugin name, will be used as part of the git clone destination
---@alias PluginCloneInfo string | string[] The git url a plugin located at or a table of arguments to be passed to `git clone`
---@alias MinPlugins table<PluginName, PluginCloneInfo>
---Downloads a plugin from a given url and registers it on the 'runtimepath'
---@param plugin_name PluginName
---@param plugin_clone_args PluginCloneInfo
function M.load_plugin(plugin_name, plugin_clone_args)
local package_root = root:push("plugins/")
local install_destination = package_root:push(plugin_name):get()
vim.opt.runtimepath:append(install_destination)
if not vim.loop.fs_stat(package_root:get()) then
vim.fn.mkdir(package_root:get(), "p")
end
-- If the plugin install path already exists, we don't need to clone it again.
if not vim.loop.fs_stat(install_destination) then
print(string.format("[LOAD PLUGIN] Downloading plugin '%s' to '%s'", plugin_name, install_destination))
if type(plugin_clone_args) == "table" then
plugin_clone_args = table.concat(plugin_clone_args, " ")
end
vim.fn.system({
"git",
"clone",
"--depth=1",
plugin_clone_args,
install_destination,
})
if vim.v.shell_error > 0 then
error(
string.format("[LOAD PLUGIN] Failed to clone plugin: '%s' to '%s'!", plugin_name, install_destination),
vim.log.levels.ERROR
)
end
end
print(("[LOAD PLUGIN] Loaded plugin '%s'"):format(plugin_name))
end
---Do the initial setup. Downloads plugins, ensures the minimal init does not pollute the filesystem by keeping
---everything self contained to the CWD of the minimal init file. Run prior to running tests, reproducing issues, etc.
---@param plugins? MinPlugins
function M.setup(plugins)
print("[SETUP] Setting up minimal init")
-- Instead of disabling swap and a bunch of other stuff, we override default xdg locations for
-- Neovim so our test client is as close to a normal client in terms of options as possible
local xdg_root = root:push("xdg")
local std_paths = {
"cache",
"data",
"config",
"state",
}
for _, std_path in pairs(std_paths) do
local xdg_str = "XDG_" .. std_path:upper() .. "_HOME"
local xdg_path = xdg_root:push(std_path):get()
print(("[SETUP] Set vim.env.%-3s -> %s"):format(xdg_str, xdg_path))
vim.env[xdg_str] = xdg_path
---@diagnostic disable-next-line: param-type-mismatch
vim.fn.mkdir(vim.fn.stdpath(std_path), "p")
end
-- Ignore cleanups if specified in the environment
-- NOTE: Cleanup the xdg cache on exit so new runs of the minimal init doesn't share any previous state, e.g. shada
vim.api.nvim_create_autocmd("VimLeave", {
callback = function()
if vim.env.TEST_NO_CLEANUP and vim.env.TEST_NO_CLEANUP:lower() == "true" then
print("[CLEANUP]: `TEST_NO_CLEANUP` was specified, not removing: " .. xdg_root)
else
print("[CLEANUP]: `TEST_NO_CLEANUP` not specified, removing " .. xdg_root)
vim.fn.delete(xdg_root:get(), "rf")
end
end,
})
-- Empty the package path so we use only the plugins specified
vim.opt.packpath = {}
-- Install required plugins
if plugins ~= nil then
for plugin_name, plugin_clone_args in pairs(plugins) do
M.load_plugin(plugin_name, plugin_clone_args)
end
end
-- Ensure `nvim-ts-autotag` is registed on the runtimepath and set it up
utils.rtp_register_ts_autotag()
require("nvim-ts-autotag").setup({
enable = true,
enable_rename = true,
enable_close = true,
enable_close_on_slash = true,
})
print("[SETUP] Finished setting up minimal init")
end
M.setup({
["plenary.nvim"] = "https://github.com/nvim-lua/plenary.nvim",
["popup.nvim"] = "https://github.com/nvim-lua/popup.nvim",
["nvim-treesitter"] = "https://github.com/nvim-treesitter/nvim-treesitter",
["playground"] = "https://github.com/nvim-treesitter/playground",
["nvim-treesitter-rescript"] = "https://github.com/nkrkv/nvim-treesitter-rescript",
})

View File

@ -1,326 +0,0 @@
local ts = require 'nvim-treesitter.configs'
ts.setup({
ensure_installed = _G.ts_filetypes,
highlight = {
use_languagetree = false,
enable = true,
},
fold = { enable = false },
})
local data = {
{
name = 'html rename open tag',
filepath = './sample/index.html',
filetype = 'html',
linenr = 10,
key = [[ciwlala]],
before = [[<di|v> dsadsa </div> ]],
after = [[<lala|> dsadsa </lala> ]],
},
{
name = 'html rename open tag with attr',
filepath = './sample/index.html',
filetype = 'html',
linenr = 10,
key = [[ciwlala]],
before = [[<di|v class="lla"> dsadsa </div> ]],
after = [[<lala| class="lla"> dsadsa </lala|> ]],
},
{
name = 'html rename close tag with attr',
filepath = './sample/index.html',
filetype = 'html',
linenr = 10,
key = [[ciwlala]],
before = [[<div class="lla"> dsadsa </di|v> ]],
after = [[<lala class="lla"> dsadsa </lal|a> ]],
},
{
name = 'html not rename close tag on char <',
filepath = './sample/index.html',
filetype = 'html',
linenr = 10,
key = [[i<]],
before = [[<div class="lla"> dsadsa |/button> ]],
after = [[<div class="lla"> dsadsa <|/button> ]],
},
{
name = 'html not rename close tag with not valid',
filepath = './sample/index.html',
filetype = 'html',
linenr = 12,
key = [[ciwlala]],
before = {
[[<di|v class="lla" ]],
[[ dsadsa </div>]],
},
after = [[<lala class="lla" ]],
},
-- {
-- only=true,
-- name = "html not rename close tag if it have parent node map with child nod" ,
-- filepath = './sample/index.html',
-- filetype = "html",
-- linenr = 12,
-- key = [[ciwlala]],
-- before = {
-- [[<d|iv> </div>]],
-- [[<div> </div>"]]
-- },
-- after = [[<d|iv> </div>]]
-- },
{
name = 'html not rename close tag with not valid',
filepath = './sample/index.html',
filetype = 'html',
linenr = 12,
key = [[ciwlala]],
before = {
[[<div class="lla" </d|iv>]],
},
after = [[<div class="lla" </lala|>]],
},
{
name = 'typescriptreact rename open tag',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
linenr = 12,
key = [[ciwlala]],
before = [[<di|v> dsadsa </div> ]],
after = [[<lala|> dsadsa </lala> ]],
},
{
name = 'typescriptreact rename open tag with attr',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
linenr = 12,
key = [[ciwlala]],
before = [[<di|v class="lla"> dsadsa </div> ]],
after = [[<lala| class="lla"> dsadsa </lala> ]],
},
{
name = 'typescriptreact rename close tag with attr',
filepath = './sample/index.tsx',
filetype = 'html',
linenr = 12,
key = [[ciwlala]],
before = [[<div class="lla"> dsadsa </di|v> ]],
after = [[<lala class="lla"> dsadsa </lal|a> ]],
},
{
name = '17 typescriptreact nested indentifer ',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
linenr = 12,
key = [[ciwlala]],
before = [[<Opt.In|put></Opt.Input> ]],
after = [[<Opt.lala|></Opt.lala> ]],
},
{
name = '18 rename empty node ',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
linenr = 12,
key = [[ilala]],
before = [[<|><div></div></>]],
after = [[<lala|><div></div></lala>]],
},
{
name = '19 rename start tag on svelte ',
filepath = './sample/index.svelte',
filetype = 'svelte',
linenr = 18,
key = [[ciwlala]],
before = [[<|data></data>]],
after = [[<lala|></lala>]],
},
{
name = '20 rename end tag on svelte ',
filepath = './sample/index.svelte',
filetype = 'svelte',
linenr = 18,
key = [[ciwlala]],
before = [[<span></spa|n>]],
after = [[<lala></lala>]],
},
{
name = "21 rescript rename open tag",
filepath = './sample/index.res',
filetype = "rescript",
linenr = 12,
key = [[ciwlala]],
before = [[<di|v> dsadsa </div> ]],
after = [[<lala|> dsadsa </lala> ]]
},
{
name = "22 rescript rename open tag with attr",
filepath = './sample/index.res',
filetype = "rescript",
linenr = 12,
key = [[ciwlala]],
before = [[<di|v class="lla"> dsadsa </div> ]],
after = [[<lala| class="lla"> dsadsa </lala> ]]
},
{
name = "23 rescript rename close tag with attr",
filepath = './sample/index.res',
filetype = "rescript",
linenr = 12,
key = [[ciwlala]],
before = [[<div class="lla"> dsadsa </di|v> ]],
after = [[<lala class="lla"> dsadsa </lal|a> ]]
},
{
name = '24 test check rename same with parent',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
linenr = 12,
key = 'ciwkey',
before = {
'<Container>',
' <di|v>',
'',
' <span></span>',
'</Container>',
},
after = {
'<Container>',
' <key>',
'',
' <span></span>',
'</Container>',
},
},
{
name = '25 rename start have same node with parent',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
linenr = 12,
key = [[ciwlala]],
before = {
'<div>',
' <di|v>',
' <span>test </span>',
' </div>',
'</div>',
},
after = {
'<div>',
' <lala>',
' <span>test </span>',
' </lala>',
'</div>',
},
},
{
name = '26 rename should not rename tag on attribute node',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
linenr = 12,
key = [[ciwlala]],
before = {
'<div>',
'<Navbar className="|a">',
' <div className="flex flex-col">',
' <div className="flex flex-row">',
' </div>',
' </div>',
'</div>',
},
after = {
'<div>',
'<Navbar className="lala">',
' <div className="flex flex-col">',
' <div className="flex flex-row">',
' </div>',
' </div>',
'</div>',
},
},
{
name = 'eruby rename open tag',
filepath = './sample/index.html.erb',
filetype = 'eruby',
linenr = 10,
key = [[ciwlala]],
before = [[<di|v> dsadsa </div> ]],
after = [[<lala|> dsadsa </lala> ]],
},
{
name = 'eruby rename open tag with attr',
filepath = './sample/index.html.erb',
filetype = 'eruby',
linenr = 10,
key = [[ciwlala]],
before = [[<di|v class="lla"> dsadsa </div> ]],
after = [[<lala| class="lla"> dsadsa </lala|> ]],
},
{
name = 'eruby rename close tag with attr',
filepath = './sample/index.html.erb',
filetype = 'eruby',
linenr = 10,
key = [[ciwlala]],
before = [[<div class="lla"> dsadsa </di|v> ]],
after = [[<lala class="lla"> dsadsa </lal|a> ]],
},
{
name = 'eruby not rename close tag on char <',
filepath = './sample/index.html.erb',
filetype = 'eruby',
linenr = 10,
key = [[i<]],
before = [[<div class="lla"> dsadsa |/button> ]],
after = [[<div class="lla"> dsadsa <|/button> ]],
},
{
name = 'eruby not rename close tag with not valid',
filepath = './sample/index.html.erb',
filetype = 'eruby',
linenr = 12,
key = [[ciwlala]],
before = {
[[<di|v class="lla" ]],
[[ dsadsa </div>]],
},
after = [[<lala class="lla" ]],
},
{
name = 'eruby not rename close tag with not valid',
filepath = './sample/index.html.erb',
filetype = 'eruby',
linenr = 12,
key = [[ciwlala]],
before = {
[[<div class="lla" </d|iv>]],
},
after = [[<div class="lla" </lala|>]],
},
{
name = 'eruby not rename tag-like ruby string',
filepath = './sample/index.html.erb',
filetype = 'eruby',
linenr = 12,
key = [[ciwlala]],
before = {
[[<%= <div></d|iv> %>]],
},
after = [[<%= <div></lala|> %>]],
},
}
local autotag = require('nvim-ts-autotag')
autotag.test = true
local run_data = _G.Test_filter(data)
describe('[rename tag]', function()
_G.Test_withfile(run_data, {
cursor_add = 0,
before_each = function(value) end,
})
end)

View File

@ -1,167 +1,167 @@
local ts = require('nvim-treesitter.configs')
ts.setup({
ensure_installed = _G.ts_filetypes,
local helpers = require("tests.utils.helpers")
helpers.setup_nvim_treesitter({
highlight = { enable = true },
})
local data = {
{
name = '1 html close tag after inputting /',
filepath = './sample/index.html',
filetype = 'html',
name = "1 html close tag after inputting /",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[/]],
before = [[<div><| ]],
after = [[<div></div>|]],
},
{
name = '2 html close tag after inputting /',
filepath = './sample/index.html',
filetype = 'html',
name = "2 html close tag after inputting /",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[/]],
before = [[<div clas="laa"><| ]],
after = [[<div clas="laa"></div>|]],
},
{
name = '3 html don\'t close tag when no opening tag is found',
filepath = './sample/index.html',
filetype = 'html',
name = "3 html don't close tag when no opening tag is found",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[/>]],
before = [[<div><|</div> ]],
after = [[<div></>|</div>]],
},
{
name = '4 html not close inside quote',
filepath = './sample/index.html',
filetype = 'html',
name = "4 html not close inside quote",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[/]],
before = [[<div class="aa|"> </div> ]],
after = [[<div class="aa/|"> </div> ]],
},
{
name = '5 typescriptreact close tag after inputting /',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "5 typescriptreact close tag after inputting /",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[/]],
before = [[<Img><| ]],
after = [[<Img></Img>| ]],
},
{
name = '6 typescriptreact close after inputting /',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "6 typescriptreact close after inputting /",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[/]],
before = [[<div class="abc"><| ]],
after = [[<div class="abc"></div>| ]],
},
{
name = '7 typescriptreact close on inline script after inputting /',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "7 typescriptreact close on inline script after inputting /",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 9,
key = [[/]],
before = [[const a = () => <div><| ]],
after = [[const a = () => <div></div>| ]],
},
{
name = '8 typescriptreact not close on close tag',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "8 typescriptreact not close on close tag",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[/]],
before = [[<button className="btn " onClick={()}> <| ]],
after = [[<button className="btn " onClick={()}> </button>| ]],
},
{
name = '9 typescriptreact not close on expresion',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "9 typescriptreact not close on expresion",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[/]],
before = [[<button className="btn " onClick={(|)}> </button> ]],
after = [[<button className="btn " onClick={(/|)}> </button> ]],
},
{
name = '10 typescriptreact not close on typescript',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "10 typescriptreact not close on typescript",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 6,
key = [[/]],
before = [[const data:Array<string| ]],
after = [[const data:Array<string/| ]],
},
{
name = '11 typescriptreact not close on script',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "11 typescriptreact not close on script",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 6,
key = [[/]],
before = [[{(card.data | 0) && <div></div>}]],
after = [[{(card.data /| 0) && <div></div>}]],
},
{
name = '12 vue close tag after inputting /',
filepath = './sample/index.vue',
filetype = 'vue',
name = "12 vue close tag after inputting /",
filepath = "./sample/index.vue",
filetype = "vue",
linenr = 4,
key = [[/]],
before = [[<Img><| ]],
after = [[<Img></Img>|]],
},
{
name = '13 vue not close on script',
filepath = './sample/index.vue',
filetype = 'vue',
name = "13 vue not close on script",
filepath = "./sample/index.vue",
filetype = "vue",
linenr = 12,
key = [[/]],
before = [[const data:Array<string| ]],
after = [[const data:Array<string/| ]],
},
{
name = '14 typescriptreact nested indentifer close after inputting /',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "14 typescriptreact nested indentifer close after inputting /",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[/]],
before = [[<Opt.Input><| ]],
after = [[<Opt.Input></Opt.Input>| ]],
},
{
name = '15 php close tag after inputting /',
filepath = './sample/index.php',
filetype = 'php',
name = "15 php close tag after inputting /",
filepath = "./sample/index.php",
filetype = "php",
linenr = 25,
key = [[/]],
before = [[<div><| ]],
after = [[<div></div>| ]],
},
{
name = '16 lit template div close after inputting /',
filepath = './sample/index.ts',
filetype = 'typescript',
name = "16 lit template div close after inputting /",
filepath = "./sample/index.ts",
filetype = "typescript",
linenr = 3,
key = [[/]],
before = [[<div><| ]],
after = [[<div></div>| ]],
},
{
name = '17 eruby template div close after inputting /',
filepath = './sample/index.html.erb',
filetype = 'eruby',
name = "17 eruby template div close after inputting /",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 10,
key = [[/]],
before = [[<div><| ]],
after = [[<div></div>| ]],
},
{
name = '18 eruby template ruby string write raw /',
filepath = './sample/index.html.erb',
filetype = 'eruby',
name = "18 eruby template ruby string write raw /",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 10,
key = [[/]],
before = [[<%= <div| %>]],
@ -169,13 +169,13 @@ local data = {
},
}
local autotag = require('nvim-ts-autotag')
local autotag = require("nvim-ts-autotag")
autotag.test = true
local run_data = _G.Test_filter(data)
local run_data = helpers.Test_filter(data)
describe('[close slash tag]', function()
_G.Test_withfile(run_data, {
mode = 'i',
describe("[close slash tag]", function()
helpers.Test_withfile(run_data, {
mode = "i",
cursor_add = 0,
})
end)

View File

@ -1,95 +1,95 @@
local ts = require('nvim-treesitter.configs')
ts.setup({
ensure_installed = _G.ts_filetypes,
local helpers = require("tests.utils.helpers")
helpers.setup_nvim_treesitter({
highlight = { enable = true },
})
local data = {
{
name = '1 html close tag',
filepath = './sample/index.html',
filetype = 'html',
name = "1 html close tag",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[>]],
before = [[<div| ]],
after = [[<div>|</div>]],
},
{
name = '2 html close tag',
filepath = './sample/index.html',
filetype = 'html',
name = "2 html close tag",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[>]],
before = [[<div clas="laa"| ]],
after = [[<div clas="laa">|</div>]],
},
{
name = '3 html not close tag on close tag',
filepath = './sample/index.html',
filetype = 'html',
name = "3 html not close tag on close tag",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[>]],
before = [[<div>aa</div| ]],
after = [[<div>aa</div>|]],
},
{
name = '4 html not close on input tag',
filepath = './sample/index.html',
filetype = 'html',
name = "4 html not close on input tag",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[>]],
before = [[<input| ]],
after = [[<input>| ]],
},
{
name = '5 html not close inside quote',
filepath = './sample/index.html',
filetype = 'html',
name = "5 html not close inside quote",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[>]],
before = [[<div class="aa|"> </div> ]],
after = [[<div class="aa>|"> </div> ]],
},
{
name = '6 html not close on exist tag',
filepath = './sample/index.html',
filetype = 'html',
name = "6 html not close on exist tag",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[>]],
before = [[<div><div|</div></div>]],
after = [[<div><div>|</div></div>]],
},
{
name = '7 typescriptreact close tag',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "7 typescriptreact close tag",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[>]],
before = [[<Img| ]],
after = [[<Img>|</Img> ]],
},
{
name = '8 typescriptreact close',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "8 typescriptreact close",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[>]],
before = [[<div class="abc"| ]],
after = [[<div class="abc">|</div> ]],
},
{
name = '9 typescriptreact not close on exist tag',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "9 typescriptreact not close on exist tag",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[>]],
before = [[<div><div|</div></div>]],
after = [[<div><div>|</div></div>]],
},
{
name = '10 typescriptreact close on inline script',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "10 typescriptreact close on inline script",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 9,
key = [[>]],
before = [[const a = () => <div| ]],
@ -97,27 +97,27 @@ local data = {
},
{
name = '11 typescriptreact not close on close tag',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "11 typescriptreact not close on close tag",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[>]],
before = [[<button className="btn " onClick={()}> </button| ]],
after = [[<button className="btn " onClick={()}> </button>| ]],
},
{
name = '12 typescriptreact not close on expresion',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "12 typescriptreact not close on expresion",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[>]],
before = [[<button className="btn " onClick={(|)}> </button> ]],
after = [[<button className="btn " onClick={(>|)}> </button> ]],
},
{
name = '13 typescriptreact not close on typescript',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "13 typescriptreact not close on typescript",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 6,
key = [[>]],
before = [[const data:Array<string| ]],
@ -125,45 +125,45 @@ local data = {
},
{
name = '14 typescriptreact not close on script',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "14 typescriptreact not close on script",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 6,
key = [[>]],
before = [[{(card.data | 0) && <div></div>}]],
after = [[{(card.data >| 0) && <div></div>}]],
},
{
name = '15 vue auto close tag',
filepath = './sample/index.vue',
filetype = 'vue',
name = "15 vue auto close tag",
filepath = "./sample/index.vue",
filetype = "vue",
linenr = 4,
key = [[>]],
before = [[<Img| ]],
after = [[<Img>|</Img>]],
},
{
name = '16 vue not close on script',
filepath = './sample/index.vue',
filetype = 'vue',
name = "16 vue not close on script",
filepath = "./sample/index.vue",
filetype = "vue",
linenr = 12,
key = [[>]],
before = [[const data:Array<string| ]],
after = [[const data:Array<string>| ]],
},
{
name = '17 typescriptreact nested indentifer ',
filepath = './sample/index.tsx',
filetype = 'typescriptreact',
name = "17 typescriptreact nested indentifer ",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[>]],
before = [[<Opt.Input| ]],
after = [[<Opt.Input>|</Opt.Input> ]],
},
{
name = '18 php div ',
filepath = './sample/index.php',
filetype = 'php',
name = "18 php div ",
filepath = "./sample/index.php",
filetype = "php",
linenr = 25,
key = [[>]],
before = [[<div| ]],
@ -179,27 +179,27 @@ local data = {
-- after = [[<div>|</div> ]],
-- },
{
name = '19 lit template div',
filepath = './sample/index.ts',
filetype = 'typescript',
name = "19 lit template div",
filepath = "./sample/index.ts",
filetype = "typescript",
linenr = 3,
key = [[>]],
before = [[<div| ]],
after = [[<div>|</div> ]],
},
{
name = '20 eruby template div',
filepath = './sample/index.html.erb',
filetype = 'eruby',
name = "20 eruby template div",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 10,
key = [[>]],
before = [[<div| ]],
after = [[<div>|</div> ]],
},
{
name = '20 eruby template ruby string',
filepath = './sample/index.html.erb',
filetype = 'eruby',
name = "20 eruby template ruby string",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 10,
key = [[>]],
before = [[<%= <div| %>]],
@ -207,14 +207,14 @@ local data = {
},
}
local autotag = require('nvim-ts-autotag')
local autotag = require("nvim-ts-autotag")
autotag.test = true
local run_data = _G.Test_filter(data)
local run_data = helpers.Test_filter(data)
describe('[close tag]', function()
_G.Test_withfile(run_data, {
mode = 'i',
describe("[close tag]", function()
helpers.Test_withfile(run_data, {
mode = "i",
cursor_add = 0,
before_each = function(value) end,
before_each = function() end,
})
end)

View File

@ -0,0 +1,325 @@
local helpers = require("tests.utils.helpers")
helpers.setup_nvim_treesitter({
highlight = {
use_languagetree = false,
enable = true,
},
fold = { enable = false },
})
local data = {
{
name = "html rename open tag",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[ciwlala]],
before = [[<di|v> dsadsa </div> ]],
after = [[<lala|> dsadsa </lala> ]],
},
{
name = "html rename open tag with attr",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[ciwlala]],
before = [[<di|v class="lla"> dsadsa </div> ]],
after = [[<lala| class="lla"> dsadsa </lala|> ]],
},
{
name = "html rename close tag with attr",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[ciwlala]],
before = [[<div class="lla"> dsadsa </di|v> ]],
after = [[<lala class="lla"> dsadsa </lal|a> ]],
},
{
name = "html not rename close tag on char <",
filepath = "./sample/index.html",
filetype = "html",
linenr = 10,
key = [[i<]],
before = [[<div class="lla"> dsadsa |/button> ]],
after = [[<div class="lla"> dsadsa <|/button> ]],
},
{
name = "html not rename close tag with not valid",
filepath = "./sample/index.html",
filetype = "html",
linenr = 12,
key = [[ciwlala]],
before = {
[[<di|v class="lla" ]],
[[ dsadsa </div>]],
},
after = [[<lala class="lla" ]],
},
-- {
-- only=true,
-- name = "html not rename close tag if it have parent node map with child nod" ,
-- filepath = './sample/index.html',
-- filetype = "html",
-- linenr = 12,
-- key = [[ciwlala]],
-- before = {
-- [[<d|iv> </div>]],
-- [[<div> </div>"]]
-- },
-- after = [[<d|iv> </div>]]
-- },
{
name = "html not rename close tag with not valid",
filepath = "./sample/index.html",
filetype = "html",
linenr = 12,
key = [[ciwlala]],
before = {
[[<div class="lla" </d|iv>]],
},
after = [[<div class="lla" </lala|>]],
},
{
name = "typescriptreact rename open tag",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[ciwlala]],
before = [[<di|v> dsadsa </div> ]],
after = [[<lala|> dsadsa </lala> ]],
},
{
name = "typescriptreact rename open tag with attr",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[ciwlala]],
before = [[<di|v class="lla"> dsadsa </div> ]],
after = [[<lala| class="lla"> dsadsa </lala> ]],
},
{
name = "typescriptreact rename close tag with attr",
filepath = "./sample/index.tsx",
filetype = "html",
linenr = 12,
key = [[ciwlala]],
before = [[<div class="lla"> dsadsa </di|v> ]],
after = [[<lala class="lla"> dsadsa </lal|a> ]],
},
{
name = "17 typescriptreact nested indentifer ",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[ciwlala]],
before = [[<Opt.In|put></Opt.Input> ]],
after = [[<Opt.lala|></Opt.lala> ]],
},
{
name = "18 rename empty node ",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[ilala]],
before = [[<|><div></div></>]],
after = [[<lala|><div></div></lala>]],
},
{
name = "19 rename start tag on svelte ",
filepath = "./sample/index.svelte",
filetype = "svelte",
linenr = 18,
key = [[ciwlala]],
before = [[<|data></data>]],
after = [[<lala|></lala>]],
},
{
name = "20 rename end tag on svelte ",
filepath = "./sample/index.svelte",
filetype = "svelte",
linenr = 18,
key = [[ciwlala]],
before = [[<span></spa|n>]],
after = [[<lala></lala>]],
},
{
name = "21 rescript rename open tag",
filepath = "./sample/index.res",
filetype = "rescript",
linenr = 12,
key = [[ciwlala]],
before = [[<di|v> dsadsa </div> ]],
after = [[<lala|> dsadsa </lala> ]],
},
{
name = "22 rescript rename open tag with attr",
filepath = "./sample/index.res",
filetype = "rescript",
linenr = 12,
key = [[ciwlala]],
before = [[<di|v class="lla"> dsadsa </div> ]],
after = [[<lala| class="lla"> dsadsa </lala> ]],
},
{
name = "23 rescript rename close tag with attr",
filepath = "./sample/index.res",
filetype = "rescript",
linenr = 12,
key = [[ciwlala]],
before = [[<div class="lla"> dsadsa </di|v> ]],
after = [[<lala class="lla"> dsadsa </lal|a> ]],
},
{
name = "24 test check rename same with parent",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = "ciwkey",
before = {
"<Container>",
" <di|v>",
"",
" <span></span>",
"</Container>",
},
after = {
"<Container>",
" <key>",
"",
" <span></span>",
"</Container>",
},
},
{
name = "25 rename start have same node with parent",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[ciwlala]],
before = {
"<div>",
" <di|v>",
" <span>test </span>",
" </div>",
"</div>",
},
after = {
"<div>",
" <lala>",
" <span>test </span>",
" </lala>",
"</div>",
},
},
{
name = "26 rename should not rename tag on attribute node",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[ciwlala]],
before = {
"<div>",
'<Navbar className="|a">',
' <div className="flex flex-col">',
' <div className="flex flex-row">',
" </div>",
" </div>",
"</div>",
},
after = {
"<div>",
'<Navbar className="lala">',
' <div className="flex flex-col">',
' <div className="flex flex-row">',
" </div>",
" </div>",
"</div>",
},
},
{
name = "eruby rename open tag",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 10,
key = [[ciwlala]],
before = [[<di|v> dsadsa </div> ]],
after = [[<lala|> dsadsa </lala> ]],
},
{
name = "eruby rename open tag with attr",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 10,
key = [[ciwlala]],
before = [[<di|v class="lla"> dsadsa </div> ]],
after = [[<lala| class="lla"> dsadsa </lala|> ]],
},
{
name = "eruby rename close tag with attr",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 10,
key = [[ciwlala]],
before = [[<div class="lla"> dsadsa </di|v> ]],
after = [[<lala class="lla"> dsadsa </lal|a> ]],
},
{
name = "eruby not rename close tag on char <",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 10,
key = [[i<]],
before = [[<div class="lla"> dsadsa |/button> ]],
after = [[<div class="lla"> dsadsa <|/button> ]],
},
{
name = "eruby not rename close tag with not valid",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 12,
key = [[ciwlala]],
before = {
[[<di|v class="lla" ]],
[[ dsadsa </div>]],
},
after = [[<lala class="lla" ]],
},
{
name = "eruby not rename close tag with not valid",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 12,
key = [[ciwlala]],
before = {
[[<div class="lla" </d|iv>]],
},
after = [[<div class="lla" </lala|>]],
},
{
name = "eruby not rename tag-like ruby string",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 12,
key = [[ciwlala]],
before = {
[[<%= <div></d|iv> %>]],
},
after = [[<%= <div></lala|> %>]],
},
}
local autotag = require("nvim-ts-autotag")
autotag.test = true
local run_data = helpers.Test_filter(data)
describe("[rename tag]", function()
helpers.Test_withfile(run_data, {
cursor_add = 0,
before_each = function() end,
})
end)

View File

@ -1,189 +0,0 @@
local utils = require('nvim-ts-autotag.utils')
local log = require('nvim-ts-autotag._log')
local api = vim.api
local helpers = {}
function helpers.feed(text, feed_opts, is_replace)
feed_opts = feed_opts or 'n'
if not is_replace then
text = vim.api.nvim_replace_termcodes(text, true, false, true)
end
vim.api.nvim_feedkeys(text, feed_opts, true)
end
function helpers.insert(text, is_replace)
helpers.feed('i' .. text, 'x', is_replace)
end
utils.insert_char = function(text)
api.nvim_put({ text }, 'c', true, true)
end
utils.feed = function(text, num)
local result = ''
for _ = 1, num, 1 do
result = result .. text
end
api.nvim_feedkeys(
api.nvim_replace_termcodes(result, true, false, true),
'x',
true
)
end
_G.eq = assert.are.same
_G.Test_filter = function(data)
local run_data = {}
for _, value in pairs(data) do
if value.only == true then
table.insert(run_data, value)
break
end
end
if #run_data == 0 then
run_data = data
end
return run_data
end
local compare_text = function(linenr, text_after, name, cursor_add, end_cursor)
cursor_add = cursor_add or 0
local new_text = vim.api.nvim_buf_get_lines(
0,
linenr - 1,
linenr + #text_after - 1,
true
)
for i = 1, #text_after, 1 do
local t = string.gsub(text_after[i], '%|', '')
if t
and new_text[i]
and t:gsub('%s+$', '') ~= new_text[i]:gsub('%s+$', '')
then
eq(t, new_text[i], '\n\n text error: ' .. name .. '\n')
end
local p_after = string.find(text_after[i], '%|')
if p_after then
local row, col = utils.get_cursor()
if end_cursor then
eq(row, linenr + i - 2, '\n\n cursor row error: ' .. name .. '\n')
eq(
col + 1,
end_cursor,
'\n\n end cursor column error : ' .. name .. '\n'
)
else
eq(row, linenr + i - 2, '\n\n cursor row error: ' .. name .. '\n')
p_after = p_after + cursor_add
eq(
col,
math.max(p_after - 2, 0),
'\n\n cursor column error : ' .. name .. '\n'
)
end
end
end
return true
end
_G.Test_withfile = function(test_data, cb)
for _, value in pairs(test_data) do
it('test ' .. value.name, function(done)
local text_before = {}
value.linenr = value.linenr or 1
local pos_before = {
linenr = value.linenr,
colnr = 0,
}
if not vim.tbl_islist(value.before) then
value.before = { value.before }
end
for index, text in pairs(value.before) do
local txt = string.gsub(text, '%|', '')
table.insert(text_before, txt)
if string.match(text, '%|') then
if string.find(text, '%|') then
pos_before.colnr = string.find(text, '%|')
pos_before.linenr = value.linenr + index - 1
end
end
end
if not vim.tbl_islist(value.after) then
value.after = { value.after }
end
vim.bo.filetype = value.filetype or 'text'
vim.cmd(':bd!')
if cb.before_each then
cb.before_each(value)
end
if vim.fn.filereadable(vim.fn.expand(value.filepath)) == 1 then
vim.cmd(':e ' .. value.filepath)
if value.filetype then
vim.bo.filetype = value.filetype
end
vim.cmd(':e')
else
vim.cmd(':new')
if value.filetype then
vim.bo.filetype = value.filetype
end
end
vim.api.nvim_buf_set_lines(
0,
value.linenr - 1,
value.linenr + #text_before,
false,
text_before
)
vim.api.nvim_win_set_cursor(
0,
{ pos_before.linenr, pos_before.colnr - 1 }
)
log.debug('insert:' .. value.key)
if type(value.key) == 'string' then
if cb.mode == 'i' then
helpers.insert(value.key, value.not_replace_term_code)
else
helpers.feed(value.key, 'x')
end
else
for _, key in pairs(value.key) do
helpers.feed(key, 'x')
vim.wait(1)
end
end
vim.wait(2)
helpers.feed('<esc>')
compare_text(
value.linenr,
value.after,
value.name,
cb.cursor_add,
value.end_cursor
)
if cb.after_each then
cb.after_each(value)
end
vim.cmd(':bd!')
end)
end
end
_G.dump_node = function(node)
local text = utils.get_node_text(node)
for _, txt in pairs(text) do
log.debug(txt)
end
end
_G.dump_node_text = function(target)
for node in target:iter_children() do
local node_type = node:type()
local text = utils.get_node_text(node)
log.debug('type:' .. node_type .. ' ')
log.debug(text)
end
end

16
tests/test.lua Normal file
View File

@ -0,0 +1,16 @@
require("tests.minimal_init")
---@type string
local test_file = vim.v.argv[#vim.v.argv]
if test_file == "" or not test_file:find("tests/specs/", nil, true) then
test_file = "tests/specs"
end
print("[STARTUP] Running all tests in " .. test_file)
vim.cmd([[
]])
require("plenary.test_harness").test_directory(test_file, {
minimal_init = "tests/minimal_init.lua",
sequential = true,
})

177
tests/utils/helpers.lua Normal file
View File

@ -0,0 +1,177 @@
local test_utils = require("tests.utils.utils")
-- Some helpers depend on utilities from the main plugin, so we have to register the plugin on the
-- path if it isn't already present
test_utils.rtp_register_ts_autotag()
local utils = require("nvim-ts-autotag.utils")
local log = require("nvim-ts-autotag._log")
local M = {}
local helpers = {}
function helpers.feed(text, feed_opts, is_replace)
feed_opts = feed_opts or "n"
if not is_replace then
text = vim.api.nvim_replace_termcodes(text, true, false, true)
end
vim.api.nvim_feedkeys(text, feed_opts, true)
end
function helpers.insert(text, is_replace)
helpers.feed("i" .. text, "x", is_replace)
end
M.insert_char = function(text)
vim.api.nvim_put({ text }, "c", true, true)
end
M.feed = function(text, num)
local result = ""
for _ = 1, num, 1 do
result = result .. text
end
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(result, true, false, true), "x", true)
end
M.setup_nvim_treesitter = function(opts)
opts = vim.tbl_deep_extend("keep", opts or {}, {
ensure_installed = {
"html",
"javascript",
"typescript",
"svelte",
"vue",
"tsx",
"php",
"glimmer",
"rescript",
"embedded_template",
},
})
end
M.Test_filter = function(data)
local run_data = {}
for _, value in pairs(data) do
if value.only == true then
table.insert(run_data, value)
break
end
end
if #run_data == 0 then
run_data = data
end
return run_data
end
local compare_text = function(linenr, text_after, name, cursor_add, end_cursor)
cursor_add = cursor_add or 0
local new_text = vim.api.nvim_buf_get_lines(0, linenr - 1, linenr + #text_after - 1, true)
for i = 1, #text_after, 1 do
local t = string.gsub(text_after[i], "%|", "")
if t and new_text[i] and t:gsub("%s+$", "") ~= new_text[i]:gsub("%s+$", "") then
assert.are.same(t, new_text[i], "\n\n text error: " .. name .. "\n")
end
local p_after = string.find(text_after[i], "%|")
if p_after then
local row, col = utils.get_cursor()
if end_cursor then
assert.are.same(row, linenr + i - 2, "\n\n cursor row error: " .. name .. "\n")
assert.are.same(col + 1, end_cursor, "\n\n end cursor column error : " .. name .. "\n")
else
assert.are.same(row, linenr + i - 2, "\n\n cursor row error: " .. name .. "\n")
p_after = p_after + cursor_add
assert.are.same(col, math.max(p_after - 2, 0), "\n\n cursor column error : " .. name .. "\n")
end
end
end
return true
end
M.Test_withfile = function(test_data, cb)
for _, value in pairs(test_data) do
it("test " .. value.name, function()
local text_before = {}
value.linenr = value.linenr or 1
local pos_before = {
linenr = value.linenr,
colnr = 0,
}
if not vim.islist(value.before) then
value.before = { value.before }
end
for index, text in pairs(value.before) do
local txt = string.gsub(text, "%|", "")
table.insert(text_before, txt)
if string.match(text, "%|") then
if string.find(text, "%|") then
pos_before.colnr = string.find(text, "%|")
pos_before.linenr = value.linenr + index - 1
end
end
end
if not vim.islist(value.after) then
value.after = { value.after }
end
vim.bo.filetype = value.filetype or "text"
vim.cmd(":bd!")
if cb.before_each then
cb.before_each(value)
end
if vim.fn.filereadable(vim.fn.expand(value.filepath)) == 1 then
vim.cmd(":e " .. value.filepath)
if value.filetype then
vim.bo.filetype = value.filetype
end
vim.cmd(":e")
else
vim.cmd(":new")
if value.filetype then
vim.bo.filetype = value.filetype
end
end
vim.api.nvim_buf_set_lines(0, value.linenr - 1, value.linenr + #text_before, false, text_before)
vim.api.nvim_win_set_cursor(0, { pos_before.linenr, pos_before.colnr - 1 })
log.debug("insert:" .. value.key)
if type(value.key) == "string" then
if cb.mode == "i" then
helpers.insert(value.key, value.not_replace_term_code)
else
helpers.feed(value.key, "x")
end
else
for _, key in pairs(value.key) do
helpers.feed(key, "x")
vim.wait(1)
end
end
vim.wait(2)
helpers.feed("<esc>")
compare_text(value.linenr, value.after, value.name, cb.cursor_add, value.end_cursor)
if cb.after_each then
cb.after_each(value)
end
vim.cmd(":bd!")
end)
end
end
M.dump_node = function(node)
local text = utils.get_node_text(node)
for _, txt in pairs(text) do
log.debug(txt)
end
end
M.dump_node_text = function(target)
for node in target:iter_children() do
local node_type = node:type()
local text = utils.get_node_text(node)
log.debug("type:" .. node_type .. " ")
log.debug(text)
end
end
return M

77
tests/utils/paths.lua Normal file
View File

@ -0,0 +1,77 @@
local M = {}
---Search up from the current file until we find the full path of the base `tests/` directory and
---return it
---@param test_file string Filename to look for in each directory, if it exists then stop the search
---@return fun(): string dir A function wrapping the found directory
local function search_dir_up(test_file)
-- This is the path of the directory of the current file
local cur_dir = vim.fn.fnamemodify(debug.getinfo(1, "S").source:sub(2), ":p")
---@diagnostic disable-next-line: param-type-mismatch
while not vim.uv.fs_stat(cur_dir .. "/" .. test_file, nil) and cur_dir ~= "/" do
cur_dir = vim.fn.fnamemodify(cur_dir, ":h")
end
if cur_dir == "/" then
error("Failed to locate the base 'tests/' directory!")
end
-- We return a wrapping function instead of a bare string so its easier to enforce "readonly"
-- uses of the searched directory
return function()
return cur_dir
end
end
--- WARN: DO NOT MUTATE THESE VALUES!
---
--- Table containing useful paths to directories within the plugin
M.static = {
--- Full path of the `tests/` directory
tests_dir = search_dir_up("test.lua"),
--- Full base path of the plugin where the `.git` directory resides
ts_autotag_dir = search_dir_up(".git"),
}
---@class nvim-ts-autotag.Root
---@field package path string
local Root = {
path = M.static.tests_dir(),
}
---@package
---@nodiscard
---@return nvim-ts-autotag.Root
function Root:new(o)
o = o or {}
setmetatable(o, self)
-- The last part of the path must be a "/" to work correctly
if self.path:sub(#self.path, #self.path) ~= "/" then
self.path = self.path .. "/"
end
self.__index = self
return o
end
--- Create a new instance, pushing the given path onto it
---@nodiscard
---@param path string The new path to add
---@return nvim-ts-autotag.Root
function Root:push(path)
local new_root = self:new()
-- Since we're extending the path, the current path must be a directory, ensure it ends in a "/"
if new_root.path:sub(#new_root.path) ~= "/" then
new_root.path = new_root.path .. "/"
end
new_root.path = new_root.path .. path
return new_root
end
--- Get the current path string
---@return string path
function Root:get()
return self.path
end
M.Root = Root:new()
return M

14
tests/utils/utils.lua Normal file
View File

@ -0,0 +1,14 @@
local path_utils = require("tests.utils.paths")
local M = {}
M.paths = path_utils
--- Register the main plugin (`nvim-ts-autotag`) on the runtimepath if it hasn't already been
--- registered
M.rtp_register_ts_autotag = function()
if not vim.list_contains(vim.opt.runtimepath, path_utils.static.ts_autotag_dir()) then
vim.opt.runtimepath:append(path_utils.static.ts_autotag_dir())
end
end
return M