fix: not rename and close tag on some case

This commit is contained in:
zztrieuzz 2023-03-17 09:19:45 +07:00
parent 1062700edf
commit 25698e4033
6 changed files with 897 additions and 693 deletions

View File

@ -1,28 +1,32 @@
local _, ts_utils = pcall(require, 'nvim-treesitter.ts_utils')
local get_node_text = require('nvim-ts-autotag.utils').get_node_text
local configs = require'nvim-treesitter.configs'
local parsers = require'nvim-treesitter.parsers'
local configs = require('nvim-treesitter.configs')
local parsers = require('nvim-treesitter.parsers')
local log = require('nvim-ts-autotag._log')
local utils = require('nvim-ts-autotag.utils')
local M = {}
-- stylua: ignore
M.tbl_filetypes = {
'html', 'javascript', 'typescript', 'javascriptreact', 'typescriptreact', 'svelte', 'vue', 'tsx', 'jsx', 'rescript',
'xml',
'php',
'markdown',
'glimmer','handlebars','hbs',
'glimmer', 'handlebars', 'hbs',
'htmldjango'
}
-- stylua: ignore
M.tbl_skipTag = {
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'slot',
'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr','menuitem'
'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr', 'menuitem'
}
local ERROR_TAG = "ERROR"
local ERROR_TAG = 'ERROR'
-- stylua: ignore
local HTML_TAG = {
filetypes = {'html', 'php', 'xml', 'markdown', 'htmldjango'},
filetypes = { 'html', 'php', 'xml', 'markdown', 'htmldjango' },
start_tag_pattern = 'start_tag',
start_name_tag_pattern = 'tag_name',
end_tag_pattern = "end_tag",
@ -30,84 +34,94 @@ local HTML_TAG = {
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'},
skip_tag_pattern = { 'quoted_attribute_value', 'end_tag' },
}
-- stylua: ignore
local JSX_TAG = {
filetypes = {
filetypes = {
'typescriptreact', 'javascriptreact', 'javascript.jsx',
'typescript.tsx', 'javascript', 'typescript', 'rescript'},
'typescript.tsx', 'javascript', 'typescript', 'rescript'
},
start_tag_pattern = 'jsx_opening_element|start_tag',
start_name_tag_pattern = 'identifier|nested_identifier|tag_name|jsx_identifier',
end_tag_pattern = 'jsx_closing_element|end_tag',
end_name_tag_pattern = 'identifier|tag_name',
close_tag_pattern = 'jsx_closing_element|nested_identifier|jsx_identifier|erroneous_end_tag|end_tag',
close_name_tag_pattern = 'identifier|nested_identifier|jsx_identifier|erroneous_end_tag_name|tag_name',
element_tag = 'jsx_element|element',
skip_tag_pattern = {
'jsx_closing_element', 'jsx_expression', 'string', 'jsx_attribute', 'end_tag',
'string_fragment'
},
start_tag_pattern = 'jsx_opening_element',
start_name_tag_pattern = 'identifier|nested_identifier|jsx_identifier',
end_tag_pattern = "jsx_closing_element",
end_name_tag_pattern = "identifier|nested_identifier|jsx_identifier",
close_tag_pattern = 'jsx_closing_element',
close_name_tag_pattern = 'identifier|nested_identifier|jsx_identifier',
element_tag = 'jsx_element',
skip_tag_pattern = {'jsx_closing_element','jsx_expression', 'string', 'jsx_attribute'},
}
-- stylua: ignore
local HBS_TAG = {
filetypes = {'glimmer', 'handlebars','hbs'},
start_tag_pattern = 'element_node_start',
start_name_tag_pattern = 'tag_name',
end_tag_pattern = "element_node_end",
end_name_tag_pattern = "tag_name",
close_tag_pattern = 'element_node_end',
close_name_tag_pattern = 'tag_name',
element_tag = 'element_node',
skip_tag_pattern = {'element_node_end', 'attribute_node', 'concat_statement' },
filetypes = { 'glimmer', 'handlebars', 'hbs', 'htmldjango' },
start_tag_pattern = 'element_node_start',
start_name_tag_pattern = 'tag_name',
end_tag_pattern = 'element_node_end',
end_name_tag_pattern = 'tag_name',
close_tag_pattern = 'element_node_end',
close_name_tag_pattern = 'tag_name',
element_tag = 'element_node',
skip_tag_pattern = { 'element_node_end', 'attribute_node', 'concat_statement' },
}
-- stylua: ignore
local SVELTE_TAG = {
filetypes = {'svelte'},
filetypes = { 'svelte' },
start_tag_pattern = 'start_tag',
start_name_tag_pattern = 'tag_name',
end_tag_pattern = "end_tag",
end_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',
element_tag = 'element',
skip_tag_pattern = {'quoted_attribute_value', 'end_tag'},
skip_tag_pattern = { 'quoted_attribute_value', 'end_tag' },
}
local all_tag = {
HBS_TAG,
SVELTE_TAG,
JSX_TAG
JSX_TAG,
}
M.enable_rename = true
M.enable_close = true
M.enable_close = true
M.setup = function (opts)
opts = opts or {}
M.setup = function(opts)
opts = opts or {}
M.tbl_filetypes = opts.filetypes or M.tbl_filetypes
M.tbl_skipTag = opts.skip_tag or M.tbl_skipTag
M.tbl_skipTag = opts.skip_tag or M.tbl_skipTag
M.enable_rename = opts.enable_rename or M.enable_rename
M.enable_close = opts.enable_close or M.enable_close
M.enable_close = opts.enable_close or M.enable_close
end
local function is_in_table(tbl, val)
if tbl == nil then return false end
if tbl == nil then
return false
end
for _, value in pairs(tbl) do
if val== value then return true end
if val == value then
return true
end
end
return false
end
M.is_supported = function (lang)
return is_in_table(M.tbl_filetypes,lang)
M.is_supported = function(lang)
return is_in_table(M.tbl_filetypes, lang)
end
local buffer_tag={}
local buffer_tag = {}
local setup_ts_tag = function()
local bufnr = vim.api.nvim_get_current_buf()
for _,value in pairs(all_tag) do
if is_in_table(value.filetypes,vim.bo.filetype) then
for _, value in pairs(all_tag) do
if is_in_table(value.filetypes, vim.bo.filetype) then
buffer_tag[bufnr] = value
return value
end
@ -120,34 +134,43 @@ local function get_ts_tag()
end
local function find_child_match(opts)
local target = opts.target
local pattern = opts.pattern
local target = opts.target
local pattern = opts.pattern
local skip_tag_pattern = opts.skip_tag_pattern
assert(target ~= nil, "find child target not nil :" .. pattern)
for node in target:iter_children() do
local node_type = node:type()
if node_type ~= nil and
node_type == pattern and
not is_in_table(skip_tag_pattern, node_type)
then
return node
if target == nil or pattern == nil then
return nil
end
local tbl_pattern = vim.split(pattern, '|')
for _, ptn in pairs(tbl_pattern) do
for node in target:iter_children() do
local node_type = node:type()
if node_type ~= nil
and node_type == ptn
and not is_in_table(skip_tag_pattern, node_type)
then
return node
end
end
end
end
local function find_parent_match(opts)
local target = opts.target
local max_depth = opts.max_depth or 10
local pattern = opts.pattern
local target = opts.target
local max_depth = opts.max_depth or 10
local pattern = opts.pattern
local skip_tag_pattern = opts.skip_tag_pattern
assert(target ~= nil, "find parent target not nil :" .. pattern)
local cur_depth = 0
local cur_node = target
local tbl_pattern = vim.split(pattern, "|")
for _,ptn in pairs(tbl_pattern) do
if target == nil or pattern == nil then
return nil
end
local tbl_pattern = vim.split(pattern, '|')
for _, ptn in pairs(tbl_pattern) do
local cur_node = target
local cur_depth = 0
while cur_node ~= nil do
local node_type = cur_node:type()
if is_in_table(skip_tag_pattern, node_type) then return nil end
if is_in_table(skip_tag_pattern, node_type) then
return nil
end
if node_type ~= nil and node_type == ptn then
return cur_node
elseif cur_depth < max_depth then
@ -158,61 +181,69 @@ local function find_parent_match(opts)
end
end
end
return nil end
return nil
end
local function get_tag_name(node)
local tag_name = nil
if node ~= nil then
tag_name = get_node_text(node, vim.api.nvim_get_current_buf())[1]
tag_name = utils.get_node_text(node)[1]
if tag_name and #tag_name > 3 then
tag_name = tag_name:gsub('</', ''):gsub('>', ''):gsub('<', '')
end
end
return tag_name
end
local function find_tag_node(opt)
local target = opt.target or ts_utils.get_node_at_cursor()
local tag_pattern = opt.tag_pattern
local target = opt.target or ts_utils.get_node_at_cursor()
local tag_pattern = opt.tag_pattern
local name_tag_pattern = opt.name_tag_pattern
local skip_tag_pattern = opt.skip_tag_pattern
local find_child = opt.find_child or false
local find_child = opt.find_child or false
local node
if find_child then
node = find_child_match({
target = target,
pattern = tag_pattern,
skip_tag_pattern = skip_tag_pattern
node = find_child_match({
target = target,
pattern = tag_pattern,
skip_tag_pattern = skip_tag_pattern,
})
else
node = find_parent_match({
target = target,
pattern = tag_pattern,
skip_tag_pattern = skip_tag_pattern
node = find_parent_match({
target = target,
pattern = tag_pattern,
skip_tag_pattern = skip_tag_pattern,
})
end
if node == nil then return nil end
if node == nil then
return nil
end
local name_node = node
local tbl_name_pattern = {}
if string.match(name_tag_pattern,"%|") then
if string.match(name_tag_pattern, '%|') then
tbl_name_pattern = vim.split(name_tag_pattern, '|')
for _, pattern in pairs(tbl_name_pattern) do
name_node = find_child_match({
target = node,
pattern = pattern
target = node,
pattern = pattern,
})
if name_node then return name_node end
if name_node then
return name_node
end
end
end
tbl_name_pattern = vim.split(name_tag_pattern, '>')
for _, pattern in pairs(tbl_name_pattern) do
name_node = find_child_match({
target = name_node,
pattern = pattern
target = name_node,
pattern = pattern,
})
end
-- check current node is have same name of tag_match
if is_in_table(tbl_name_pattern, node:type())
then return node
if is_in_table(tbl_name_pattern, node:type()) then
return node
end
return name_node
end
@ -222,36 +253,39 @@ local function find_child_tag_node(opt)
return find_tag_node(opt)
end
local function check_close_tag()
local ts_tag = get_ts_tag()
if not ts_tag then return false end
local tag_node = find_tag_node({
tag_pattern = ts_tag.start_tag_pattern,
if not ts_tag then
return false
end
local tag_node = find_tag_node({
tag_pattern = ts_tag.start_tag_pattern,
name_tag_pattern = ts_tag.start_name_tag_pattern,
skip_tag_pattern = ts_tag.skip_tag_pattern
skip_tag_pattern = ts_tag.skip_tag_pattern,
})
if tag_node ~=nil then
if tag_node ~= nil then
local tag_name = get_tag_name(tag_node)
if tag_name ~= nil and is_in_table(M.tbl_skipTag, tag_name) then
return false
end
-- case 6,9 check close on exist node
local element_node = find_parent_match({
target = tag_node,
pattern = ts_tag.element_tag,
max_depth = 2
})
if tag_node ~= nil then
-- case 6,9 check close on exist node
local element_node = find_parent_match({
target = tag_node,
pattern = ts_tag.element_tag,
max_depth = 2,
})
local close_tag_node = find_child_tag_node({
target = element_node,
tag_pattern = ts_tag.end_tag_pattern,
name_tag_pattern = ts_tag.end_name_tag_pattern,
target = element_node,
tag_pattern = ts_tag.end_tag_pattern,
name_tag_pattern = ts_tag.end_name_tag_pattern,
})
if close_tag_node ~= nil then
local start_row = tag_node:range()
local close_start_row = close_tag_node:range()
if start_row == close_start_row and tag_name == get_tag_name(close_tag_node) then
if start_row == close_start_row
and tag_name == get_tag_name(close_tag_node)
then
return false
end
end
@ -261,35 +295,43 @@ local function check_close_tag()
return false
end
M.close_tag = function ()
M.close_tag = function()
local buf_parser = parsers.get_parser()
if not buf_parser then return end
if not buf_parser then
return
end
buf_parser:parse()
local result, tag_name = check_close_tag()
if result == true and tag_name ~= nil then
vim.cmd(string.format([[normal! a</%s>]],tag_name))
vim.cmd[[normal! F>]]
vim.cmd(string.format([[normal! a</%s>]], tag_name))
vim.cmd([[normal! F>]])
end
end
local function replace_text_node(node, tag_name)
if node == nil then return end
if node == nil then
return
end
local start_row, start_col, end_row, end_col = node:range()
if start_row == end_row then
local line = vim.fn.getline(start_row + 1)
local newline = line:sub(0, start_col) .. tag_name .. line:sub(end_col + 1, string.len(line))
vim.fn.setline(start_row + 1,{newline})
local newline = line:sub(0, start_col)
.. tag_name
.. line:sub(end_col + 1, string.len(line))
vim.fn.setline(start_row + 1, { newline })
end
end
local function validate_tag_regex(node,start_regex,end_regex)
if node == nil then return false end
local texts = get_node_text(node, vim.api.nvim_get_current_buf())
if
string.match(texts[1],start_regex)
and string.match(texts[#texts],end_regex)
then return true end
local function validate_tag_regex(node, start_regex, end_regex)
if node == nil then
return false
end
local texts = utils.get_node_text(node)
if string.match(texts[1], start_regex)
and string.match(texts[#texts], end_regex)
then
return true
end
return false
end
@ -298,88 +340,134 @@ end
-- end
local function validate_start_tag(node)
return validate_tag_regex(node,"^%<%w","%>$")
return validate_tag_regex(node, '^%<%w', '%>$')
end
local function validate_close_tag(node)
return validate_tag_regex(node,"^%<%/%w","%>$")
return validate_tag_regex(node, '^%<%/%w', '%>$')
end
local function rename_start_tag()
local ts_tag = get_ts_tag()
if not ts_tag then return end
local tag_node = find_tag_node({
tag_pattern = ts_tag.start_tag_pattern,
if not ts_tag then
return
end
local tag_node = find_tag_node({
tag_pattern = ts_tag.start_tag_pattern,
name_tag_pattern = ts_tag.start_name_tag_pattern,
skip_tag_pattern = ts_tag.skip_tag_pattern
})
if tag_node == nil then return end
if not validate_start_tag(tag_node:parent()) then return end
if tag_node == nil then
return
end
if not validate_start_tag(tag_node:parent()) then
return
end
local tag_name = get_tag_name(tag_node)
local parent_node = tag_node
tag_node = find_parent_match({
target = parent_node,
pattern = ts_tag.element_tag .. "|" .. ERROR_TAG,
max_depth = 2
tag_node = find_parent_match({
target = parent_node,
pattern = ts_tag.element_tag .. '|' .. ERROR_TAG,
max_depth = 2,
})
if tag_node == nil then return end
if tag_node == nil then
return
end
local close_tag_node = find_child_tag_node({
target = tag_node,
tag_pattern = ts_tag.close_tag_pattern,
name_tag_pattern = ts_tag.close_name_tag_pattern,
target = tag_node,
tag_pattern = ts_tag.close_tag_pattern,
name_tag_pattern = ts_tag.close_name_tag_pattern,
})
if close_tag_node == nil then
close_tag_node = find_child_tag_node({
target = tag_node:parent(),
tag_pattern = ts_tag.close_tag_pattern,
name_tag_pattern = ts_tag.close_name_tag_pattern,
})
end
if close_tag_node ~= nil then
local error_node = find_child_match({
target = tag_node,
pattern = ERROR_TAG
pattern = ERROR_TAG,
})
if error_node == nil then
log.debug('do replace')
local close_tag_name = get_tag_name(close_tag_node)
log.debug(close_tag_name)
-- verify parent node is same of close_tag_node (test case: 22)
if close_tag_node ~= nil and tag_node ~= nil then
local tag_parent = get_tag_name(tag_node:parent())
-- log.debug(utils.dump_node(tag_node:parent()))
if tag_parent == close_tag_name
and not utils.verify_node(tag_node:parent(), close_tag_name)
then
log.debug('skip it have same')
return
end
end
if tag_name ~= close_tag_name then
replace_text_node(close_tag_node, tag_name)
end
else
local error_tag = get_tag_name(error_node)
if error_tag=='</>' then
replace_text_node(error_node, "</" .. tag_name .. ">")
-- tsx node is empty
if error_tag == '</>' then
replace_text_node(error_node, '</' .. tag_name .. '>')
end
-- have both parent node and child node is error
if close_tag_node:type() == ERROR_TAG then
replace_text_node(error_node, "</" .. tag_name .. ">")
replace_text_node(error_node, '</' .. tag_name .. '>')
end
end
end
end
local function rename_end_tag()
local ts_tag = get_ts_tag()
if not ts_tag then return end
if not ts_tag then
return
end
local tag_node = find_tag_node({
tag_pattern = ts_tag.close_tag_pattern,
name_tag_pattern = ts_tag.close_name_tag_pattern,
})
-- log.debug(tag_node:type())
if tag_node == nil then
return
end
-- we check if that node text match </>
if not (validate_close_tag(tag_node:parent()) or validate_close_tag(tag_node))
then
return
end
if tag_node == nil then return end
if not validate_close_tag(tag_node:parent()) then return end
local tag_name = get_tag_name(tag_node)
tag_node = find_parent_match({
target = tag_node,
pattern = ts_tag.element_tag,
max_depth = 2
tag_node = find_parent_match({
target = tag_node,
pattern = ts_tag.element_tag,
max_depth = 2,
})
if tag_node == nil then return end
if tag_node == nil then
return
end
local start_tag_node = find_child_tag_node({
target = tag_node,
tag_pattern = ts_tag.start_tag_pattern,
name_tag_pattern = ts_tag.start_name_tag_pattern,
target = tag_node,
tag_pattern = ts_tag.start_tag_pattern,
name_tag_pattern = ts_tag.start_name_tag_pattern,
})
if not validate_start_tag(start_tag_node:parent()) then return end
if not validate_start_tag(start_tag_node:parent()) then
return
end
if start_tag_node ~= nil then
local start_tag_name = get_tag_name(start_tag_node)
if tag_name ~= start_tag_name then
@ -390,10 +478,10 @@ end
local function validate_rename()
local cursor = vim.api.nvim_win_get_cursor(0)
local line = vim.fn.getline(cursor[1])
local char = line:sub(cursor[2] + 1, cursor[2] + 1)
local line = vim.api.nvim_get_current_line()
local char = line:sub(cursor[2] + 1, cursor[2] + 1)
-- only rename when last character is a word
if string.match(char,'%w') then
if string.match(char, '%w') then
return true
end
return false
@ -407,27 +495,31 @@ M.rename_tag = function ()
end
end
M.attach = function (bufnr,lang)
M.attach = function(bufnr, lang)
M.lang = lang
local config = configs.get_module('autotag')
M.setup(config)
if is_in_table(M.tbl_filetypes, vim.bo.filetype) then
setup_ts_tag()
if M.enable_close == true then
vim.cmd[[inoremap <silent> <buffer> > ><c-c>:lua require('nvim-ts-autotag.internal').close_tag()<CR>a]]
vim.cmd(
[[inoremap <silent> <buffer> > ><c-c>:lua require('nvim-ts-autotag.internal').close_tag()<CR>a]]
)
end
if M.enable_rename == true then
bufnr = bufnr or vim.api.nvim_get_current_buf()
vim.cmd(string.format(
[[autocmd! InsertLeave <buffer=%s> call v:lua.require('nvim-ts-autotag.internal').rename_tag() ]],
bufnr
))
vim.cmd(
string.format(
[[autocmd! InsertLeave <buffer=%s> call v:lua.require('nvim-ts-autotag.internal').rename_tag() ]],
bufnr
)
)
end
end
end
M.detach = function (bufnr)
bufnr = tonumber(bufnr) or vim.api.nvim_get_current_buf()
M.detach = function()
local bufnr = vim.api.nvim_get_current_buf()
buffer_tag[bufnr] = nil
end

View File

@ -1,17 +1,31 @@
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.query.get_node_text or ts_utils.get_node_text
local M = {}
M.get_node_text = function(...)
local txt = get_node_text(...)
return vim.split(txt, '\n')
M.get_node_text = function(node)
local txt = get_node_text(node, vim.api.nvim_get_current_buf())
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
return true
end
return false
end
M.get_cursor = function(bufnr)
local row, col = unpack(vim.api.nvim_win_get_cursor(bufnr or 0))
return row - 1, col
end
M.dump_node = function(node)
local text = M.get_node_text(node)
for _, txt in pairs(text) do
print(txt)
log.debug(txt)
end
end

View File

@ -1,289 +1,209 @@
if not _G.test_close then
return
return
end
local parser_config = require "nvim-treesitter.parsers".get_parser_configs()
local ts = require 'nvim-treesitter.configs'
local ts = require('nvim-treesitter.configs')
local helpers = {}
parser_config.rescript = {
install_info = {
url = "https://github.com/nkrkv/nvim-treesitter-rescript",
files = {"src/parser.c", "src/scanner.c"},
branch = "main",
},
maintainers = { "@nkrkv" },
filetype = "rescript",
}
ts.setup {
ensure_installed = 'maintained',
highlight = {enable = true},
}
ts.setup({
ensure_installed = _G.ts_filetypes,
highlight = { enable = true },
})
local eq = assert.are.same
function helpers.feed(text, feed_opts)
feed_opts = feed_opts or 'n'
local to_feed = vim.api.nvim_replace_termcodes(text, true, false, true)
vim.api.nvim_feedkeys(to_feed, feed_opts, true)
feed_opts = feed_opts or 'n'
local to_feed = vim.api.nvim_replace_termcodes(text, true, false, true)
vim.api.nvim_feedkeys(to_feed, feed_opts, true)
end
function helpers.insert(text)
helpers.feed('a' .. text, 'x')
helpers.feed('a' .. text, 'x')
end
local data = {
{
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",
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",
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",
linenr = 10,
key = [[>]],
before = [[<input| ]],
after = [[<input>| ]]
},
{
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",
linenr = 10,
key = [[>]],
before = [[<div><div|</div></div>]],
after = [[<div><div>|</div></div>]]
},
{
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",
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",
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",
linenr = 9,
key = [[>]],
before = [[const a = () => <div|]],
after = [[const a = () => <div>|</div>]]
},
{
{
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',
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',
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',
linenr = 10,
key = [[>]],
before = [[<input| ]],
after = [[<input>| ]],
},
{
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',
linenr = 10,
key = [[>]],
before = [[<div><div|</div></div>]],
after = [[<div><div>|</div></div>]],
},
{
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',
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',
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',
linenr = 9,
key = [[>]],
before = [[const a = () => <div| ]],
after = [[const a = () => <div>|</div> ]],
},
{
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",
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",
linenr = 6,
key = [[>]],
before = [[const data:Array<string| ]],
after = [[const data:Array<string>| ]]
},
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',
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',
linenr = 6,
key = [[>]],
before = [[const data:Array<string| ]],
after = [[const data:Array<string>| ]],
},
{
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",
linenr = 4,
key = [[>]],
before = [[<Img|]],
after = [[<Img>|</Img>]]
},
{
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",
linenr = 12,
key = [[>]],
before = [[<Opt.Input| ]],
after = [[<Opt.Input>|</Opt.Input> ]]
},
{
name = "18 php div " ,
filepath = './sample/index.php',
filetype = "php",
linenr = 25,
key = [[>]],
before = [[<div| ]],
after = [[<div>|</div> ]]
},
{
name = "19 rescript close tag",
filepath = './sample/index.res',
filetype = 'rescript',
linenr = 12,
key = [[>]],
before = [[<Img|]],
after = [[<Img>|</Img>]]
},
{
name = "20 rescript close",
filepath = './sample/index.res',
filetype = 'rescript',
linenr = 13,
key = [[>]],
before = [[<div class="abc"|]],
after = [[<div class="abc">|</div>]],
},
{
name = "21 rescript not close on exist tag" ,
filepath = './sample/index.res',
filetype = "rescript",
linenr = 14,
key = [[>]],
before = [[<div><div|</div></div>]],
after = [[<div><div>|</div></div>]]
},
{
name = "22 rescript not close on close tag" ,
filepath = './sample/index.res',
filetype = "rescript",
linenr = 15,
key = [[>]],
before = [[<button onClick> </button|]],
after = [[<button onClick> </button>|]]
},
{
name = "23 rescrpt not close on expresion" ,
filepath = './sample/index.res',
filetype = "rescript",
linenr = 15,
key = [[>]],
before = [[<button onClick>{|}</button> ]],
after = [[<button onClick>{>|}</button> ]]
},
{
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',
linenr = 4,
key = [[>]],
before = [[<Img| ]],
after = [[<Img>|</Img>]],
},
{
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',
linenr = 12,
key = [[>]],
before = [[<Opt.Input| ]],
after = [[<Opt.Input>|</Opt.Input> ]],
},
{
name = '18 php div ',
filepath = './sample/index.php',
filetype = 'php',
linenr = 25,
key = [[>]],
before = [[<div| ]],
after = [[<div>|</div> ]],
},
-- {
-- name = '19 markdown div ',
-- filepath = './sample/index.md',
-- filetype = 'markdown',
-- linenr = 4,
-- key = [[>]],
-- before = [[<div| ]],
-- after = [[<div>|</div> ]],
-- },
}
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
local _, ts_utils = pcall(require, 'nvim-treesitter.ts_utils')
_G.TU=ts_utils
local function Test(test_data)
for _, value in pairs(test_data) do
it("test "..value.name, function()
local before = string.gsub(value.before , '%|' , "")
local after = string.gsub(value.after , '%|' , "")
local p_before = string.find(value.before , '%|')
local p_after = string.find(value.after , '%|')
local line =value.linenr
if vim.fn.filereadable(vim.fn.expand(value.filepath)) == 1 then
vim.cmd(":bd!")
vim.cmd(":e " .. value.filepath)
vim.bo.filetype = value.filetype
vim.fn.setline(line , before)
vim.fn.cursor(line, p_before -1)
-- autotag.closeTag()
helpers.insert(value.key)
local result = vim.fn.getline(line)
local pos = vim.fn.getpos('.')
eq(after, result , "\n\n [ERROR TEXT]: " .. value.name .. "\n")
eq(p_after, pos[3] +1, "\n\n [ERROR POS]: " .. value.name .. "\n")
else
eq(false, true, "\n\n file not exist " .. value.filepath .. "\n")
end
end)
end
end
local autotag = require('nvim-ts-autotag')
autotag.test = true
local run_data = _G.Test_filter(data)
describe('[close tag]', function()
Test(run_data)
_G.Test_withfile(run_data, {
mode = 'i',
cursor_add = 0,
before_each = function(value) end,
})
end)

View File

@ -7,6 +7,7 @@ set rtp +=../playground/
runtime! plugin/plenary.vim
runtime! plugin/nvim-treesitter.vim
runtime! plugin/playground.vim
runtime! plugin/nvim-treesitter-rescript
set noswapfile
@ -18,13 +19,18 @@ set noautoindent
set nocindent
set nosmartindent
set indentexpr=
set foldlevel=9999
lua << EOF
_G.__is_log=true
_G.test_rename = true
_G.test_close = true
_G.ts_filetypes = {
'html', 'javascript', 'typescript', 'svelte', 'vue', 'tsx', 'php', 'glimmer', 'rescript'
}
require("plenary/busted")
vim.cmd[[luafile ./tests/test-utils.lua]]
require("nvim-ts-autotag").setup()
EOF

View File

@ -1,292 +1,273 @@
local ts = require 'nvim-treesitter.configs'
local parser_config = require "nvim-treesitter.parsers".get_parser_configs()
parser_config.rescript = {
install_info = {
url = "https://github.com/nkrkv/nvim-treesitter-rescript",
files = {"src/parser.c", "src/scanner.c"},
branch = "main",
},
maintainers = { "@nkrkv" },
filetype = "rescript",
}
local log=require('nvim-ts-autotag._log')
local log = require('nvim-ts-autotag._log')
if not _G.test_rename then
return
return
end
local helpers = {}
ts.setup {
ensure_installed = 'maintained',
highlight = {
use_languagetree = true,
enable = true
},
}
local eq = assert.are.same
ts.setup({
ensure_installed = _G.ts_filetypes,
highlight = {
use_languagetree = true,
enable = true,
},
fold = { enable = false },
})
function helpers.feed(text, feed_opts)
feed_opts = feed_opts or 'n'
local to_feed = vim.api.nvim_replace_termcodes(text, true, false, true)
vim.api.nvim_feedkeys(to_feed, feed_opts, true)
feed_opts = feed_opts or 'n'
local to_feed = vim.api.nvim_replace_termcodes(text, true, false, true)
vim.api.nvim_feedkeys(to_feed, feed_opts, true)
end
function helpers.insert(text)
helpers.feed('i' .. text, 'x')
helpers.feed('i' .. text, 'x')
end
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 </lala|> ]]
},
{
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" </l|ala>]]
},
{
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 </lala|> ]]
},
{
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 = 'html rename open tag',
filepath = './sample/index.html',
filetype = 'html',
linenr = 10,
key = [[ciwlala]],
before = [[<di|v> dsadsa </div> ]],
after = [[<lala|> dsadsa </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 = '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 = "20 rename end tag on svelte " ,
filepath = './sample/index.svelte',
filetype = "svelte",
linenr = 18,
key = [[ciwlala]],
before = [[<data></da|ta>]],
after = [[<lala></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 = "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 = '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 = "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 </lala|> ]]
},
-- {
-- only = true,
-- name = "18 rename node to empty node " ,
-- filepath = './sample/index.tsx',
-- filetype = "typescriptreact",
-- linenr = 12,
-- key = [[ciw<esc>]],
-- before = [[<la|la><div></div></lala>]],
-- after = [[<|><div></div></>]]
-- },
-- TODO close tag with empty
-- {
-- only = true,
-- name = "18 rename end empty node " ,
-- filepath = './sample/index.tsx',
-- filetype = "typescriptreact",
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 = [[ilala]],
-- before = [[<span><> <div></div></|><span>]],
-- after = [[<span><|lala><div></div></lala></span>]]
-- },
-- {
-- name = "19 rename end empty node " ,
-- filepath = './sample/index.tsx',
-- filetype = "typescriptreact",
-- linenr = 12,
-- key = [[ilala]],
-- before = [[<><div></div></|>]],
-- after = [[<|lala><div></div></lala>]]
-- }
-- 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>',
},
}
}
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
local autotag = require('nvim-ts-autotag')
autotag.test = true
local function Test(test_data)
for _, value in pairs(test_data) do
it("test "..value.name, function()
local text_before={}
local pos_before={
linenr = value.linenr,
colnr=0
}
if not vim.tbl_islist(value.before) then
value.before = {value.before}
end
local numlnr = 0
for _, text in pairs(value.before) do
local txt = string.gsub(text, '%|' , "")
table.insert(text_before, txt )
if string.match( text, "%|") then
pos_before.colnr = string.find(text, '%|')
pos_before.linenr = pos_before.linenr + numlnr
end
numlnr = numlnr + 1
end
local after = string.gsub(value.after, '%|' , "")
vim.bo.filetype = value.filetype
if vim.fn.filereadable(vim.fn.expand(value.filepath)) == 1 then
vim.cmd(":bd!")
vim.cmd(":e " .. value.filepath)
local bufnr=vim.api.nvim_get_current_buf()
vim.api.nvim_buf_set_lines(bufnr, pos_before.linenr -1, pos_before.linenr +#text_before, false, text_before)
vim.fn.cursor(pos_before.linenr, pos_before.colnr)
-- autotag.renameTag()
helpers.feed(value.key, 'x')
helpers.feed("<esc>",'x')
vim.wait(10)
local result = vim.fn.getline(pos_before.linenr)
eq(after, result , "\n\n ERROR: " .. value.name .. "\n")
else
eq(false, true, "\n\n file not exist " .. value.filepath .. "\n")
end
end)
end
end
local run_data = _G.Test_filter(data)
describe('[rename tag]', function()
Test(run_data)
_G.Test_withfile(run_data, {
cursor_add = 0,
before_each = function(value) end,
})
end)

191
tests/test-utils.lua Normal file
View File

@ -0,0 +1,191 @@
local utils = require('nvim-ts-autotag.utils')
local _, ts_utils = pcall(require, 'nvim-treesitter.ts_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 = ts_utils.get_node_text(node)
for _, txt in pairs(text) do
print(txt)
end
end
_G.dump_node_text = function(target)
for node in target:iter_children() do
local node_type = node:type()
local text = ts_utils.get_node_text(node)
log.debug('type:' .. node_type .. ' ')
log.debug(text)
end
end