diff --git a/lua/nvim-ts-autotag/internal.lua b/lua/nvim-ts-autotag/internal.lua index 2459624..98ce103 100644 --- a/lua/nvim-ts-autotag/internal.lua +++ b/lua/nvim-ts-autotag/internal.lua @@ -252,6 +252,9 @@ M.close_tag = function() if result == true and tag_name ~= nil then vim.api.nvim_put({ string.format("", 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 diff --git a/lua/nvim-ts-autotag/utils.lua b/lua/nvim-ts-autotag/utils.lua index ab5e276..6b5fbdc 100644 --- a/lua/nvim-ts-autotag/utils.lua +++ b/lua/nvim-ts-autotag/utils.lua @@ -2,6 +2,65 @@ 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 {} diff --git a/sample/index.js b/sample/index.js new file mode 100644 index 0000000..072cb5d --- /dev/null +++ b/sample/index.js @@ -0,0 +1,23 @@ + +import React, { useCallback, useEffect } from 'react' + +const SamplePage = () => { + const [state, setstate] = useState(initialState) + + + return ( +
+ + + + + + + + + +
+ ) +} + +export default SamplePage diff --git a/tests/specs/closetag_spec.lua b/tests/specs/closetag_spec.lua index a48ee15..4e2284d 100644 --- a/tests/specs/closetag_spec.lua +++ b/tests/specs/closetag_spec.lua @@ -130,25 +130,7 @@ local data = { after = [[{(card.data >| 0) &&
}]], }, { - name = "15 vue auto close tag", - filepath = "./sample/index.vue", - filetype = "vue", - linenr = 4, - key = [[>]], - before = [[|]], - }, - { - name = "16 vue not close on script", - filepath = "./sample/index.vue", - filetype = "vue", - linenr = 12, - key = [[>]], - before = [[const data:Array| ]], - }, - { - 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 = [[| ]], }, { - name = "18 php div ", + name = "16 typescriptreact autoclose fragment", + filepath = "./sample/index.tsx", + filetype = "typescriptreact", + linenr = 12, + key = [[>]], + before = [[<|
]], + after = [[<>|
]], + }, + { + name = "17 javascript autoclose fragment", + filepath = "./sample/index.js", + filetype = "javascript", + linenr = 12, + key = [[>]], + before = [[<|
]], + after = [[<>|
]], + }, + { + name = "18 vue auto close tag", + filepath = "./sample/index.vue", + filetype = "vue", + linenr = 4, + key = [[>]], + before = [[|]], + }, + { + name = "19 vue not close on script", + filepath = "./sample/index.vue", + filetype = "vue", + linenr = 12, + key = [[>]], + before = [[const data:Array| ]], + }, + { + name = "20 php div ", filepath = "./sample/index.php", filetype = "php", linenr = 25, @@ -175,7 +193,7 @@ local data = { -- after = [[
|
]], -- }, { - 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 = [[
|
]], }, { - 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 = [[
|
]], }, { - 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 = [[<%=
| %> ]], }, { - 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 = [[
|
]], }, { - 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 = [[
|
]], }, { - 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 = [[
aa
|]], }, { - name = "24 templ not close on input tag", + name = "27 templ not close on input tag", filepath = "./sample/index.templ", filetype = "templ", linenr = 10,