Compare commits

...

10 Commits

Author SHA1 Message Date
Mikhail Morozov
7f9f55b285 chore: move text node filtering to utils function 2024-07-16 14:26:15 +03:00
Mikhail Morozov
0782035107 Merge branch 'main' of github.com:inferst/nvim-ts-autotag into fix/tsx-node-renaming 2024-07-15 01:46:33 +03:00
26c365cc7d
test(refactor): remove invalid test plugins (#204)
- `popup.nvim` is not referenced anywhere within the plugin and as such
  should be removed.
- `playground` is not needed either, it's not referenced and secondly
  the most important feature from it (:TSPlayground) is covered by
  Neovim's :InspectTree command in more recent versions of Neovim.

Closes #203 (https://github.com/windwp/nvim-ts-autotag/issues/203)
2024-07-14 16:47:15 -05:00
987cfa5e0f
Merge pull request #202 from roycrippen4/fix-#199
feat: support react fragments
2024-07-14 16:39:29 -05:00
roy.crippen4
33a38a53b1 chore: formatting and clarification comment 2024-07-14 17:36:32 -04:00
roycrippen4
2553ac5520
Update lua/nvim-ts-autotag/utils.lua
Co-authored-by: Price Hiller <price@orion-technologies.io>
2024-07-14 17:35:03 -04:00
roy.crippen4
cbe184f12d fix/refactor: Auto-close react fragments
Refactor: Moved detection functions into `utils.lua`
Fix: Improved react detection logic in `.js` files
2024-07-14 16:49:42 -04:00
roy.crippen4
4ab5a1fd9f test(react): Testing for auto-close react fragments in js and tsx files 2024-07-14 16:48:35 -04:00
roycrippen4
a485f97de9 Merge branch 'windwp:main' into fix-#199 2024-07-14 15:04:57 -04:00
roy.crippen4
f4528df26e fix(#199): Auto-tag react fragments
Detects if `<>` was typed in a react file (`js`, `jsx`, or `tsx`)
and autocloses the fragment tag.
2024-07-14 13:30:49 -04:00
5 changed files with 145 additions and 43 deletions

View File

@ -252,6 +252,9 @@ M.close_tag = function()
if result == true and tag_name ~= nil then
vim.api.nvim_put({ string.format("</%s>", tag_name) }, "", true, false)
vim.cmd([[normal! F>]])
elseif utils.is_react_file() and utils.is_react_fragment() then
vim.api.nvim_put({ "</>" }, "", true, false)
vim.cmd([[normal! F>]])
end
end
@ -284,20 +287,8 @@ local function validate_tag_regex(node, start_regex, end_regex)
if node == nil then
return false
end
local texts = utils.get_node_text(node)
local filtered = {}
-- For some nodes (tsx) 'vim.treesitter.get_node_text' can return empty lines or lines with spaces
-- We have to exclude them
for i = 1, #texts do
local text = texts[i]:gsub("^%s*(.-)%s*$", "%1")
if text ~= "" then
filtered[#filtered + 1] = text
end
end
if string.match(filtered[1], start_regex) and string.match(filtered[#filtered], end_regex) then
if string.match(texts[1], start_regex) and string.match(texts[#texts], end_regex) then
return true
end
return false

View File

@ -2,9 +2,81 @@ local log = require("nvim-ts-autotag._log")
local get_node_text = vim.treesitter.get_node_text
local M = {}
---@return boolean
function M.is_react_file()
local ft = vim.bo.ft
-- check filetypes first.
if ft == "javascriptreact" or ft == "typescriptreact" then
return true
elseif ft ~= "javascript" then
return false
end
-- If we are in a `javascript` file, then check the content to see if the
-- current file counts as a react file
local ok, buf_parser = pcall(vim.treesitter.get_parser)
if not ok then
return false
end
local tree = buf_parser:parse(true)
if not tree then
return false
end
local root = tree[1]:root()
local queries = { "jsx_element", "jsx_self_closing_element" }
for _, query in ipairs(queries) do
if M.node_exists(root, query) then
return true
end
end
return false
end
---@return boolean
function M.is_react_fragment()
local line = vim.fn.getline(".")
local col = vim.fn.col(".") - 2
local strpart = vim.fn.strpart(line, col)
local char_at_cursor = vim.fn.strcharpart(strpart, 0, 1) ---@type string
return char_at_cursor == "<"
end
---@param node TSNode
---@param query string
---@return boolean
function M.node_exists(node, query)
if node:type() == query then
return true
end
for child in node:iter_children() do
if M.node_exists(child, query) then
return true
end
end
return false
end
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 {}
local texts = vim.split(txt, "\n")
local filtered = {}
-- For some nodes (tsx) 'vim.treesitter.get_node_text' can return empty lines or lines with spaces
-- We have to exclude them
for i = 1, #texts do
local text = texts[i]:gsub("^%s*(.-)%s*$", "%1")
if text ~= "" then
filtered[#filtered + 1] = text
end
end
return filtered or {}
end
-- Stolen from nvim `0.10.0` for `0.9.5` users

23
sample/index.js Normal file
View File

@ -0,0 +1,23 @@
import React, { useCallback, useEffect } from 'react'
const SamplePage = () => {
const [state, setstate] = useState(initialState)
return (
<div className="h-full">
</div>
)
}
export default SamplePage

View File

@ -138,7 +138,5 @@ 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",
})

View File

@ -130,25 +130,7 @@ local data = {
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 ",
name = "15 typescriptreact nested indentifer ",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
@ -157,7 +139,43 @@ local data = {
after = [[<Opt.Input>|</Opt.Input> ]],
},
{
name = "18 php div ",
name = "16 typescriptreact autoclose fragment",
filepath = "./sample/index.tsx",
filetype = "typescriptreact",
linenr = 12,
key = [[>]],
before = [[<|<div></div>]],
after = [[<>|</><div></div>]],
},
{
name = "17 javascript autoclose fragment",
filepath = "./sample/index.js",
filetype = "javascript",
linenr = 12,
key = [[>]],
before = [[<|<div></div>]],
after = [[<>|</><div></div>]],
},
{
name = "18 vue auto close tag",
filepath = "./sample/index.vue",
filetype = "vue",
linenr = 4,
key = [[>]],
before = [[<Img| ]],
after = [[<Img>|</Img>]],
},
{
name = "19 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 = "20 php div ",
filepath = "./sample/index.php",
filetype = "php",
linenr = 25,
@ -175,7 +193,7 @@ local data = {
-- after = [[<div>|</div> ]],
-- },
{
name = "19 lit template div",
name = "21 lit template div",
filepath = "./sample/index.ts",
filetype = "typescript",
linenr = 3,
@ -184,7 +202,7 @@ local data = {
after = [[<div>|</div> ]],
},
{
name = "20 eruby template div",
name = "22 eruby template div",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 10,
@ -193,7 +211,7 @@ local data = {
after = [[<div>|</div> ]],
},
{
name = "20 eruby template ruby string",
name = "23 eruby template ruby string",
filepath = "./sample/index.html.erb",
filetype = "eruby",
linenr = 10,
@ -202,7 +220,7 @@ local data = {
after = [[<%= <div>| %> ]],
},
{
name = "21 templ close tag",
name = "24 templ close tag",
filepath = "./sample/index.templ",
filetype = "templ",
linenr = 10,
@ -211,7 +229,7 @@ local data = {
after = [[<div>|</div>]],
},
{
name = "22 templ close tag",
name = "25 templ close tag",
filepath = "./sample/index.templ",
filetype = "templ",
linenr = 10,
@ -220,7 +238,7 @@ local data = {
after = [[<div clas="laa">|</div>]],
},
{
name = "23 templ not close tag on close tag",
name = "26 templ not close tag on close tag",
filepath = "./sample/index.templ",
filetype = "templ",
linenr = 10,
@ -229,7 +247,7 @@ local data = {
after = [[<div>aa</div>|]],
},
{
name = "24 templ not close on input tag",
name = "27 templ not close on input tag",
filepath = "./sample/index.templ",
filetype = "templ",
linenr = 10,